Open cjhelloletsgo opened 8 months ago
Hi
I was able to deploy it with UntrustedArtifactOnDeployment.ENFORCE
with cdk v2.133.0.
Please check my code in TypeScript:
const signingProfile = new signer.SigningProfile(this, 'SigningProfile', {
platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA,
});
const codeSigningConfig = new lambda.CodeSigningConfig(this, 'CodeSigningConfig', {
signingProfiles: [signingProfile],
untrustedArtifactOnDeployment: lambda.UntrustedArtifactOnDeployment.ENFORCE,
});
new lambda.Function(this, 'Function', {
codeSigningConfig,
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
});
synth
Resources:
SigningProfile2139A0F9:
Type: AWS::Signer::SigningProfile
Properties:
PlatformId: AWSLambda-SHA384-ECDSA
SignatureValidityPeriod:
Type: MONTHS
Value: 135
Metadata:
aws:cdk:path: dummy-stack4/SigningProfile/Resource
CodeSigningConfigD8D41C10:
Type: AWS::Lambda::CodeSigningConfig
Properties:
AllowedPublishers:
SigningProfileVersionArns:
- Fn::GetAtt:
- SigningProfile2139A0F9
- ProfileVersionArn
CodeSigningPolicies:
UntrustedArtifactOnDeployment: Enforce
Metadata:
aws:cdk:path: dummy-stack4/CodeSigningConfig/Resource
FunctionServiceRole675BB04A:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Metadata:
aws:cdk:path: dummy-stack4/Function/ServiceRole/Resource
Function76856677:
Type: AWS::Lambda::Function
Properties:
Code:
S3Bucket: cdk-hnb659fds-assets-903779448426-us-east-1
S3Key: 297e4961275717170c4e122c4dd6e629b83080796b88b6716027321ec3f4e2c7.zip
CodeSigningConfigArn:
Fn::GetAtt:
- CodeSigningConfigD8D41C10
- CodeSigningConfigArn
Handler: index.handler
Role:
Fn::GetAtt:
- FunctionServiceRole675BB04A
- Arn
Runtime: nodejs18.x
DependsOn:
- FunctionServiceRole675BB04A
Metadata:
aws:cdk:path: dummy-stack4/Function/Resource
aws:asset:path: asset.297e4961275717170c4e122c4dd6e629b83080796b88b6716027321ec3f4e2c7
aws:asset:is-bundled: false
aws:asset:property: Code
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/2WPzw6CMAzGn8X7qCKJ8Sokng0+ABljkPJnS+jQw7J3twM8GE9f+/3afO0Z0iyD00G+KVHNkIxYg386qQbBVuUJO6NntljRdI/ZtjhqUbTm1wlilFPdSPCFbfTOCmta7OLwv3lfjHJoTaTfOgiUE/jSbglRg6CskkTaEdyicA/5ogbtckmMS012mZUWK+XLO85Yt3cQhOFw6On4Sq+QXvjZnhCTeTEOJw3lph8kXNDoCQEAAA==
Metadata:
aws:cdk:path: dummy-stack4/CDKMetadata/Default
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
cdk deploy
works great to me. And I can see this from the lambda console.
Is your error coming from cloudformation? Can you share your cdk synth
template? I believe it should work.
Sure, this is the template it generates:
Resources:
TestSigningProfile98254211:
Type: AWS::Signer::SigningProfile
Properties:
PlatformId: AWSLambda-SHA384-ECDSA
SignatureValidityPeriod:
Type: MONTHS
Value: 135
Metadata:
aws:cdk:path: IssueStack/Test Signing Profile/Resource
TestCodeSigningConfig2952C7DC:
Type: AWS::Lambda::CodeSigningConfig
Properties:
AllowedPublishers:
SigningProfileVersionArns:
- Fn::GetAtt:
- TestSigningProfile98254211
- ProfileVersionArn
CodeSigningPolicies:
UntrustedArtifactOnDeployment: Enforce
Description: Test
Metadata:
aws:cdk:path: IssueStack/Test Code Signing Config/Resource
TestLambdaServiceRoleECB4CB18:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- Fn::Join:
- ""
- - "arn:"
- Ref: AWS::Partition
- :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Metadata:
aws:cdk:path: IssueStack/Test Lambda/ServiceRole/Resource
TestLambda93B0066B:
Type: AWS::Lambda::Function
Properties:
Architectures:
- x86_64
Code:
S3Bucket: cdk-hnb659fds-assets-308665918648-us-east-1
S3Key: 851da26868933e8ab521e3bc2c318bd2a7f9220284d9b35ce3ab5c31fce99feb.zip
CodeSigningConfigArn:
Fn::GetAtt:
- TestCodeSigningConfig2952C7DC
- CodeSigningConfigArn
Description: Test Lambda delete later.
Handler: lambda_function.lambda_handler
MemorySize: 256
Role:
Fn::GetAtt:
- TestLambdaServiceRoleECB4CB18
- Arn
Runtime: python3.12
DependsOn:
- TestLambdaServiceRoleECB4CB18
Metadata:
aws:cdk:path: IssueStack/Test Lambda/Resource
aws:asset:path: asset.851da26868933e8ab521e3bc2c318bd2a7f9220284d9b35ce3ab5c31fce99feb
aws:asset:is-bundled: false
aws:asset:property: Code
TestLambdaEventInvokeConfig9F084114:
Type: AWS::Lambda::EventInvokeConfig
Properties:
FunctionName:
Ref: TestLambda93B0066B
MaximumRetryAttempts: 0
Qualifier: $LATEST
Metadata:
aws:cdk:path: IssueStack/Test Lambda/EventInvokeConfig/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/2WO0W7CMAxFv4X31IzmC6Bi0t5Q+wHIpG7w2jpSnYJQlH9HBbZp4ulY99jWLWFjLXys8KqFa/ti4BOkJqLrDV71mJS90ASpYS8s/jCFjgcyVSf/k2wGHE8tQqpCSy9XBenYL8vv4ecsLnKQxf7O+wtJ/JJL6Onv9i3MhnGEVIdnkYXZqD2iKkWF7QKjFnaz6ynuUCmbmjTMkyPzsE1Ez/L4/iOyOdziOcjawqaEcvWtzMU0S+SRoH7yDppk/rctAQAA
Metadata:
aws:cdk:path: IssueStack/CDKMetadata/Default
Parameters:
BootstrapVersion:
Type: AWS::SSM::Parameter::Value<String>
Default: /cdk-bootstrap/hnb659fds/version
Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]
Rules:
CheckBootstrapVersion:
Assertions:
- Assert:
Fn::Not:
- Fn::Contains:
- - "1"
- "2"
- "3"
- "4"
- "5"
- Ref: BootstrapVersion
AssertDescription: CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.
As well as the entire stack if that helps
from aws_cdk import (
Stack,
)
from aws_cdk import aws_lambda as lambda_
from aws_cdk import aws_signer as signer
from constructs import Construct
class IssueStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
test_signing_profile = signer.SigningProfile(
self,
"Test Signing Profile",
platform=signer.Platform.AWS_LAMBDA_SHA384_ECDSA,
)
test_code_signing_config = lambda_.CodeSigningConfig(
self,
"Test Code Signing Config",
signing_profiles=[
test_signing_profile,
],
description="Test",
# setting untrusted_artifact_on_deployment to ENFORCE causes deployment to fail
untrusted_artifact_on_deployment=lambda_.UntrustedArtifactOnDeployment.ENFORCE,
)
test_lambda = lambda_.Function(
self,
"Test Lambda",
runtime=lambda_.Runtime.PYTHON_3_12,
handler="lambda_function.lambda_handler",
code_signing_config=test_code_signing_config,
code=lambda_.Code.from_asset(
"lambda/test",
),
memory_size=256,
architecture=lambda_.Architecture.X86_64,
retry_attempts=0,
description="Test Lambda delete later.",
initial_policy=[],
)
And a screenshot to match yours
So everything seems good except the lambda will always fail to deploy.
@pahud Have you got a chance to look into this any more?
This is still a problem, I have a repo here to help reproduce the problem. https://github.com/cjhelloletsgo/cdk_signing_profile_issue
Yes now I can reproduce this
export class DummyStack extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
const signingProfile = new signer.SigningProfile(this, 'SigningProfile', {
platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA,
});
const codeSigningConfig = new lambda.CodeSigningConfig(this, 'CodeSigningConfig', {
signingProfiles: [signingProfile],
untrustedArtifactOnDeployment: lambda.UntrustedArtifactOnDeployment.ENFORCE,
});
const myFunction = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_LATEST,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda')),
codeSigningConfig: codeSigningConfig,
});
}
}
6:41:26 PM | CREATE_FAILED | AWS::Lambda::Function | MyFunction Resource handler returned message: "Lambda cannot deploy the function. The function or layer might be signed u sing a signature that the client is not configured to accept. Check the provided signature for dummy-stackk-My Function3BAA72D1-wrnBDfNVr1Ik." (RequestToken: d6b8497f-0573-c147-72f4-f5264e22883f, HandlerErrorCode: Invalid Request)
CDK v2.158.0
synth
{
"Resources": {
"SigningProfile2E013C934": {
"Type": "AWS::Signer::SigningProfile",
"Properties": {
"PlatformId": "AWSLambda-SHA384-ECDSA",
"SignatureValidityPeriod": {
"Type": "MONTHS",
"Value": 135
}
},
"Metadata": {
"aws:cdk:path": "dummy-stackk/SigningProfile2/Resource"
}
},
"CodeSigningConfig202ACE0C5": {
"Type": "AWS::Lambda::CodeSigningConfig",
"Properties": {
"AllowedPublishers": {
"SigningProfileVersionArns": [
{
"Fn::GetAtt": [
"SigningProfile2E013C934",
"ProfileVersionArn"
]
}
]
},
"CodeSigningPolicies": {
"UntrustedArtifactOnDeployment": "Enforce"
}
},
"Metadata": {
"aws:cdk:path": "dummy-stackk/CodeSigningConfig2/Resource"
}
},
"MyFunctionServiceRole3C357FF2": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
},
"Metadata": {
"aws:cdk:path": "dummy-stackk/MyFunction/ServiceRole/Resource"
}
},
"MyFunction3BAA72D1": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "cdk-hnb659fds-assets-903779448426-us-east-1",
"S3Key": "3988ba077676d6ed0bb4481ec971bf54da0c66e1ff656338ecfe5b3a001c5511.zip"
},
"CodeSigningConfigArn": {
"Fn::GetAtt": [
"CodeSigningConfig202ACE0C5",
"CodeSigningConfigArn"
]
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"MyFunctionServiceRole3C357FF2",
"Arn"
]
},
"Runtime": "nodejs18.x"
},
"DependsOn": [
"MyFunctionServiceRole3C357FF2"
],
"Metadata": {
"aws:cdk:path": "dummy-stackk/MyFunction/Resource",
"aws:asset:path": "asset.3988ba077676d6ed0bb4481ec971bf54da0c66e1ff656338ecfe5b3a001c5511",
"aws:asset:is-bundled": false,
"aws:asset:property": "Code"
}
},
"CDKMetadata": {
"Type": "AWS::CDK::Metadata",
"Properties": {
"Analytics": "v2:deflate64:H4sIAAAAAAAA/2WNwWrDQAxEvyV3WXUSQnttDD0X+wOCspYXxbYWrHVyWPbfg+P4UHp6w7yBOeD+9IXljh5WuLYvBrliaiK5Huhhl2TilSdMjXgV9b9T6GRgqDr922QYaLy2hKkKLb9dFbQTv4z/lz+zuihBF7vlDEIjpjqsDwsz2PFCZhwNvxeAHfE8u57jmYwz1GxhnhzDyzaRvOjrchMZNLSMN/u4H0rcf2K5u5lIMc0aZWSsVz4BnGZHOQkBAAA="
},
"Metadata": {
"aws:cdk:path": "dummy-stackk/CDKMetadata/Default"
}
}
},
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}
I am making it a p1 bug now.
Thank you!
@cjhelloletsgo FYI we are still investigating. Will let you know shortly if we have any updates.
Looks like it's Lambda service's responsibility to proceed the signing operation but I can't find relevant document about it.
I'll cut an internal ticket for clarifying.
internal tracking: V1521555433
I believe it's relevant to https://github.com/aws/aws-cdk/issues/12216#issuecomment-784290273 which mentioned that CDK actually didn't sign the bundle from local and https://github.com/aws/aws-cdk-rfcs/issues/305 was attempting to address that but was closed. At this moment, I am afraid you need to sign the bundle using AWS CLI start-signing-job or from the AWS Signer console.
We still welcome any idea to continue from where https://github.com/aws/aws-cdk-rfcs/issues/305#issuecomment-1858352721 was stopped. I will submit a small PR to mention that in the lambda doc.
From reading through those links it seems this is broken with no plans of being fixed? Are you saying I can use start-signing-job somehow in the bundling options? Doing it through the signer console doesn't make sense as I am deploying through the CLI how would that be possible?
Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one.
Comments on closed issues and PRs are hard for our team to see. If you need help, please open a new issue that references this one.
From reading through those links it seems this is broken with no plans of being fixed? Are you saying I can use start-signing-job somehow in the bundling options? Doing it through the signer console doesn't make sense as I am deploying through the CLI how would that be possible?
Yes unfortunately CDK CLI at this moment does not support it out-of-the-box and the experience would not be expected.
My workaround here. This is not great but it explains how it works in action.
cdk synth
to synthesize assets into cdk.out
.npx cdk-assets -p cdk.out/your_stack_name.assets.json publish
#!/bin/sh
set -x
ZIP_FILE='a5936dcaa6ccdbc6eacb1209c70d2eed716e9040937124c26b5cc53b954846a0.zip'
PROFILE_NAME='SigningProfile2139A0F9_IvT8c6lPa2rl'
BUCKET='cdk-hnb659fds-assets-123456789012-us-east-1'
LATEST_VERSION=$(aws s3api list-object-versions \
--bucket $BUCKET \
--prefix $ZIP_FILE \
--query 'Versions[0].VersionId' \
--output text)
JOB_ID=$(aws signer start-signing-job \
--source "s3={bucketName=$BUCKET,key=$ZIP_FILE, version=$LATEST_VERSION}" \
--destination "s3={bucketName=$BUCKET,prefix=signed-}" \
--profile-name $PROFILE_NAME --query 'jobId' --output text)
sleep 2
# get the signedObject s3 key
newObjectKey=$(aws signer describe-signing-job --job-id $JOB_ID --query signedObject.s3.key --output text)
# rename the signed object to origin object name
aws s3 mv s3://$BUCKET/$newObjectKey s3://$BUCKET/$ZIP_FILE
cdk deploy
, it should work!If you are comfortable with python, this is my proof of concept(by Amazon Q Developer), you can revise and build your own tool like this before CDK CLI has native support for that.
import json, boto3, time
# Path to your JSON file
file_path = '/Your/Path/To/cdk.out/dummy-stack.assets.json'
profile_name = 'SigningProfile2139A0F9_IvT8c6lPa2rl'
# Function to parse the JSON and extract required information
def parse_assets_json(file_path):
with open(file_path, 'r') as file:
data = json.load(file)
assets = []
for asset_id, asset_info in data.get('files', {}).items():
source = asset_info.get('source', {})
destinations = asset_info.get('destinations', {})
# Get the first destination (assuming there's only one)
destination = next(iter(destinations.values()), {})
packaging = source.get('packaging')
object_key = destination.get('objectKey')
bucket_name = destination.get('bucketName')
if packaging == 'zip' and object_key and bucket_name:
assets.append({
'assetId': asset_id,
'packaging': packaging,
'objectKey': object_key,
'bucketName': bucket_name
})
return assets
# get_latest_version()
def get_latest_version(s3, bucket_name, object_key):
response = s3.list_object_versions(
Bucket=bucket_name,
Prefix=object_key,
MaxKeys=1
)
if 'Versions' in response and response['Versions']:
return response['Versions'][0]['VersionId']
return None
def sign_s3_object(bucket_name, object_key, profile_name, destination_bucket=None):
# Initialize AWS clients
session = boto3.Session()
s3 = session.client('s3')
signer = session.client('signer')
my_account = session.client('sts').get_caller_identity()['Account']
# If destination bucket is not specified, use the source bucket
if not destination_bucket:
destination_bucket = bucket_name
# Start the signing job
response = signer.start_signing_job(
source={
's3': {
'bucketName': bucket_name,
'key': object_key,
'version': get_latest_version(s3, bucket_name, object_key)
}
},
destination={
's3': {
'bucketName': destination_bucket,
'prefix': 'sign-',
}
},
profileName=profile_name
)
job_id = response['jobId']
print(f"Signing job started. Job ID: {job_id}")
# sleep 5 seconds
time.sleep(5)
# get signed_object_key from a new describing signing job call
response = signer.describe_signing_job(jobId=job_id)
print(response)
signed_object_key = response['signedObject'].get('s3').get('key')
# Wait for the signing job to complete
while True:
response = signer.describe_signing_job(jobId=job_id)
status = response['status']
if status == 'Succeeded':
break
elif status in ['Failed', 'Revoked']:
raise Exception(f"Signing job failed with status: {status}")
time.sleep(5) # Wait for 5 seconds before checking again
# Get the signed object key
print(f"Signing completed. Signed object key: {signed_object_key}")
# Move the signed object to replace the original object
s3.copy_object(
Bucket=bucket_name,
CopySource={'Bucket': destination_bucket, 'Key': signed_object_key},
Key=object_key,
ExpectedBucketOwner=my_account,
ExpectedSourceBucketOwner=my_account,
)
print(f"Signed object moved to original key: {object_key}")
# Delete the temporary signed object
s3.delete_object(Bucket=destination_bucket, Key=signed_object_key)
print(f"Temporary signed object deleted: {signed_object_key}")
return object_key
# Parse the JSON file
result = parse_assets_json(file_path)
# Print the results
for asset in result:
print(f"Asset ID: {asset['assetId']}")
print(f"Object Key: {asset['objectKey']}")
print(f"Bucket Name: {asset['bucketName']}")
print("---")
# sign the object
sign_s3_object(asset['bucketName'], asset['objectKey'], profile_name=profile_name)
Output:
Signing completed. Signed object key: sign-5e21daf1-d34e-4233-bbe2-e63207d7c914.zip Signed object moved to original key: a5936dcaa6ccdbc6eacb1209c70d2eed716e9040937124c26b5cc53b954846a0.zip Temporary signed object deleted: sign-5e21daf1-d34e-4233-bbe2-e63207d7c914.zip
Now, I just reopened this issue as p2 feature request.
We welcome community PRs and please help us prioritize with 👍 on the issue description.
Describe the bug
While configuring code signing on an aws lambda if you specify a code signing config where the untrusted_artifact_on_deployment parameter is set to ENFORCE the deployment will always fail. If the policy is set to warn there is no problem.
Expected Behavior
The lambda to be signed using the code signing configuration
Current Behavior
The code fails to deploy with an error message: Lambda cannot deploy the function. The function or layer might be signed using a signature that the client is not configured to accept. Check the provided signature for LAMBDA_ARN_HERE
Reproduction Steps
Create a stack with the above resources, try to deploy a lambda with warn, it will work. Try to deploy the lambda with enforce, it will not work
Possible Solution
No response
Additional Information/Context
No response
CDK CLI Version
2.132.1
Framework Version
No response
Node.js Version
v20.11.1
OS
Ubuntu 23.10
Language
Python
Language Version
Python 3.11
Other information
No response