Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CL-522 | Add SignerSigningJob module to revoke signing jobs #3

Merged
merged 4 commits into from
May 1, 2023

Conversation

gsoria
Copy link

@gsoria gsoria commented Apr 26, 2023

This PR includes a new module to handle Signer signing jobs. Signing jobs are viewable by the ListSigningJobs operation for two years after they are performed [1] As a precaution we are updating Signing jobs statuses to revoked. This indicates that the signature is no longer valid.

[1] https://awscli.amazonaws.com/v2/documentation/api/latest/reference/signer/start-signing-job.html

Testing

Tests were performed using existing test scripts for AWS signer. Credits to @corybekk

# generate lambda function
echo "def lambda_handler(event, context):
    print('AWS Cookbook Function run at {}'.format(str(datetime.now())))" >> lambda_function.py

# zip up the code
zip lambda_function.zip lambda_function.py

RANDOM_STRING=$(aws secretsmanager get-random-password \
--exclude-punctuation --exclude-uppercase \
--password-length 6 --require-each-included-type \
--output text \
--query RandomPassword)

# Create a Destination S3 bucket to store the signed code:
aws s3api create-bucket --bucket awscookbook505-dst-$RANDOM_STRING

# Create a Source S3 Bucket to store the raw code:
aws s3api create-bucket --bucket awscookbook505-src-$RANDOM_STRING

# Enable Versioning for the Source S3 bucket (this is required by AWS Signer):
aws s3api put-bucket-versioning \
--bucket awscookbook505-src-$RANDOM_STRING \
--versioning-configuration Status=Enabled

# Copy the provided lambda_function.zip file that contains the source code to the Source S3 bucket:
aws s3 cp ./lambda_function.zip s3://awscookbook505-src-$RANDOM_STRING

# Get the version of the object in S3 that you will use. This is a zip of the code to be used in your Lambda function. You’ll need this when you are starting the signing job:
OBJ_VER_ID=$(aws s3api list-object-versions \
--bucket awscookbook505-src-$RANDOM_STRING \
--prefix lambda_function.zip \
--output text --query Versions[0].VersionId)

# Create a signing profile:
SIGNING_PROFILE_ARN=$(aws signer put-signing-profile \
--profile-name AWSCookbook505_$RANDOM_STRING \
--platform AWSLambda-SHA384-ECDSA \
--output text --query arn)

# You can find a list of the available signing platforms by running this command:
aws signer list-signing-platforms

# Create a code signing configuration for Lambda that refers to the signing profile:
CODE_SIGNING_CONFIG_ARN=$(aws lambda create-code-signing-config \
--allowed-publishers SigningProfileVersionArns=$SIGNING_PROFILE_ARN \
--output text --query CodeSigningConfig.CodeSigningConfigArn)


# Start the signing job:
SIGNING_JOB_ID=$(aws signer start-signing-job \
--source 's3={bucketName=awscookbook505-src-'"${RANDOM_STRING}"',key=lambda_function.zip,version='"$OBJ_VER_ID"'}' \
--destination 's3={bucketName=awscookbook505-dst-'"${RANDOM_STRING}"',prefix=signed-}' \
--profile-name AWSCookbook505_$RANDOM_STRING \
	--output text --query jobId)

# Wait a few moments and then verify that the signing job was successful with:
sleep 5
aws signer list-signing-jobs --status Succeeded

Listing the signing jobs, we can see the signing job f79fa22e-e4be-4751-a91b-93184bf68d57 with "isRevoked": false,.

{
    "jobs": [
        {
            "jobId": "f79fa22e-e4be-4751-a91b-93184bf68d57",
            "source": {
                "s3": {
                    "bucketName": "awscookbook505-src-m7t3lv",
                    "key": "lambda_function.zip",
                    "version": "Cn1GD_vK0WmFwKxJmdPupm3qCD6wjXQb"
                }
            },
            "signedObject": {
                "s3": {
                    "bucketName": "awscookbook505-dst-m7t3lv",
                    "key": "signed-f79fa22e-e4be-4751-a91b-93184bf68d57.zip"
                }
            },
            "signingMaterial": {},
            "createdAt": "2023-04-26T22:12:13+00:00",
            "status": "Succeeded",
            "isRevoked": false,
            "profileName": "AWSCookbook505_m7t3lv",
            "profileVersion": "hvSmz12bhb",
            "platformId": "AWSLambda-SHA384-ECDSA",
            "platformDisplayName": "AWS Lambda",
            "signatureExpiresAt": "2034-07-26T22:12:13+00:00",
            "jobOwner": "239624814509",
            "jobInvoker": "239624814509"
        },
        {
            "jobId": "e46b6cc6-ace8-4e8e-9dba-83834badaa9d",
            "source": {
                "s3": {
                    "bucketName": "awscookbook505-src-uc5r7t",
                    "key": "lambda_function.zip",
                    "version": "4DDtQKYfprIHd90hYGs.r91RRZqslFsu"
                }
            },
            "signedObject": {
                "s3": {
                    "bucketName": "awscookbook505-dst-uc5r7t",
                    "key": "signed-e46b6cc6-ace8-4e8e-9dba-83834badaa9d.zip"
                }
            },
            "signingMaterial": {},
            "createdAt": "2023-04-26T21:17:57+00:00",
            "status": "Succeeded",
            "isRevoked": true,
            "profileName": "AWSCookbook505_uc5r7t",
            "profileVersion": "cB9aR4BoYS",
            "platformId": "AWSLambda-SHA384-ECDSA",
            "platformDisplayName": "AWS Lambda",
            "signatureExpiresAt": "2034-07-26T21:17:58+00:00",
            "jobOwner": "239624814509",
            "jobInvoker": "239624814509"
        }
    ]
}

Using this new module, aws-nuke the signing job was revoked as expected:

us-east-1 - SignerSigningJob - [JobId: "f79fa22e-e4be-4751-a91b-93184bf68d57"] - triggered remove
Removal requested: 1 waiting, 0 failed, 0 skipped, 0 finished
us-east-1 - SignerSigningJob - [JobId: "f79fa22e-e4be-4751-a91b-93184bf68d57"] - waiting
Removal requested: 1 waiting, 0 failed, 0 skipped, 0 finished
us-east-1 - SignerSigningJob - [JobId: "f79fa22e-e4be-4751-a91b-93184bf68d57"] - removed
Removal requested: 0 waiting, 0 failed, 0 skipped, 1 finished
Nuke complete: 0 failed, 0 skipped, 1 finished.

When verifying the signing jobs again, we can see the signing job f79fa22e-e4be-4751-a91b-93184bf68d57 with "isRevoked": true,

{
    "jobs": [
        {
            "jobId": "f79fa22e-e4be-4751-a91b-93184bf68d57",
            "source": {
                "s3": {
                    "bucketName": "awscookbook505-src-m7t3lv",
                    "key": "lambda_function.zip",
                    "version": "Cn1GD_vK0WmFwKxJmdPupm3qCD6wjXQb"
                }
            },
            "signedObject": {
                "s3": {
                    "bucketName": "awscookbook505-dst-m7t3lv",
                    "key": "signed-f79fa22e-e4be-4751-a91b-93184bf68d57.zip"
                }
            },
            "signingMaterial": {},
            "createdAt": "2023-04-26T22:12:13+00:00",
            "status": "Succeeded",
            "isRevoked": true,
            "profileName": "AWSCookbook505_m7t3lv",
            "profileVersion": "hvSmz12bhb",
            "platformId": "AWSLambda-SHA384-ECDSA",
            "platformDisplayName": "AWS Lambda",
            "signatureExpiresAt": "2034-07-26T22:12:13+00:00",
            "jobOwner": "239624814509",
            "jobInvoker": "239624814509"
        },
        {
            "jobId": "e46b6cc6-ace8-4e8e-9dba-83834badaa9d",
            "source": {
                "s3": {
                    "bucketName": "awscookbook505-src-uc5r7t",
                    "key": "lambda_function.zip",
                    "version": "4DDtQKYfprIHd90hYGs.r91RRZqslFsu"
                }
            },
            "signedObject": {
                "s3": {
                    "bucketName": "awscookbook505-dst-uc5r7t",
                    "key": "signed-e46b6cc6-ace8-4e8e-9dba-83834badaa9d.zip"
                }
            },
            "signingMaterial": {},
            "createdAt": "2023-04-26T21:17:57+00:00",
            "status": "Succeeded",
            "isRevoked": true,
            "profileName": "AWSCookbook505_uc5r7t",
            "profileVersion": "cB9aR4BoYS",
            "platformId": "AWSLambda-SHA384-ECDSA",
            "platformDisplayName": "AWS Lambda",
            "signatureExpiresAt": "2034-07-26T21:17:58+00:00",
            "jobOwner": "239624814509",
            "jobInvoker": "239624814509"
        }
    ]

Signing jobs are viewable by the ListSigningJobs operation for two years after they are performed [1]
As a precaution we are updating Signing jobs statuses to revoked. This indicates that the signature is no longer valid.

[1] https://awscli.amazonaws.com/v2/documentation/api/latest/reference/signer/start-signing-job.html

Signed-off-by: Gabriela S. Soria <gsoria@oreilly.com>
Copy link
Member

@sstoops sstoops left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, @gsoria ! I left a few minor suggestions inline that I think may help align some functionality with other upstream modules.

resources/signer.signingjobs.go Outdated Show resolved Hide resolved
resources/signer.signingjobs.go Outdated Show resolved Hide resolved

func (j *SignerSigningJob) Properties() types.Properties {
properties := types.NewProperties()
properties.Set("JobId", j.jobId)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think any of the other (many) properties returned by ListSigningJobs would be good to add to properties for users to be able to filter on?

I was thinking maybe createdAt, profile*, platform*, job* attributes? I know I see a lot of aws nuke code changes to add more and more properties to give users more powerful filtering.

{
    'jobs': [
        {
            'jobId': 'string',
            'source': {
                's3': {
                    'bucketName': 'string',
                    'key': 'string',
                    'version': 'string'
                }
            },
            'signedObject': {
                's3': {
                    'bucketName': 'string',
                    'key': 'string'
                }
            },
            'signingMaterial': {
                'certificateArn': 'string'
            },
            'createdAt': datetime(2015, 1, 1),
            'status': 'InProgress'|'Failed'|'Succeeded',
            'isRevoked': True|False,
            'profileName': 'string',
            'profileVersion': 'string',
            'platformId': 'string',
            'platformDisplayName': 'string',
            'signatureExpiresAt': datetime(2015, 1, 1),
            'jobOwner': 'string',
            'jobInvoker': 'string'
        },
    ],
    'NextToken': 'string'
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my first approach, I didn't think much about filtering these jobs. Thanks for the suggestions, I included more properties as part of 2fae9cc. As we discuss in the meeting yesterday, instead of including the job in the struct, I included only the properties I wanted to use. Let me know what you think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to my untrained eye! I'm still a bit unsure when to use a pointer like you have in your type def. I think the way you have it should keep it performant.

Signed-off-by: Gabriela S. Soria <gsoria@oreilly.com>
Signed-off-by: Gabriela S. Soria <gsoria@oreilly.com>
Signed-off-by: Gabriela S. Soria <gsoria@oreilly.com>
@gsoria gsoria requested a review from sstoops April 28, 2023 19:48
Copy link
Member

@danarbaugh danarbaugh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following your testing procedure with your branches, I was able to recreate your intended behavior.

Before aws-nuke:

$ aws signer list-signing-jobs --status Succeeded
{
    "jobs": [
        {
            "jobId": "db882524-902e-4bd6-ac03-a66df08e73a0",
            "source": {
                "s3": {
                    "bucketName": "awscookbook505-src-pl42eg",
                    "key": "lambda_function.zip",
                    "version": "cbIsFsfeGezV8l6IkH2bDLhAAe_5sjgk"
                }
            },
            "signedObject": {
                "s3": {
                    "bucketName": "awscookbook505-dst-pl42eg",
                    "key": "signed-db882524-902e-4bd6-ac03-a66df08e73a0.zip"
                }
            },
            "signingMaterial": {},
            "createdAt": "2023-04-28T22:03:08+00:00",
            "status": "Succeeded",
            "isRevoked": false,
            "profileName": "AWSCookbook505_pl42eg",
            "profileVersion": "ELAcw04kNv",
            "platformId": "AWSLambda-SHA384-ECDSA",
            "platformDisplayName": "AWS Lambda",
            "signatureExpiresAt": "2034-07-28T22:03:08+00:00",
            "jobOwner": "430037344291",
            "jobInvoker": "430037344291"
        }
    ]
}

Found by aws-nuke:

us-east-1 - SignerSigningJob - [CreatedAt: "2023-04-28T22:03:08Z", JobId: "db882524-902e-4bd6-ac03-a66df08e73a0", JobInvoker: "430037344291", JobOwner: "430037344291", PlatformDisplayName: "AWS Lambda", PlatformId: "AWSLambda-SHA384-ECDSA", ProfileName: "AWSCookbook505_pl42eg", ProfileVersion: "ELAcw04kNv"] - would remove

Successfully nuked:

us-east-1 - SignerSigningJob - [CreatedAt: "2023-04-28T22:03:08Z", JobId: "db882524-902e-4bd6-ac03-a66df08e73a0", JobInvoker: "430037344291", JobOwner: "430037344291", PlatformDisplayName: "AWS Lambda", PlatformId: "AWSLambda-SHA384-ECDSA", ProfileName: "AWSCookbook505_pl42eg", ProfileVersion: "ELAcw04kNv"] - removed

Subsequent list-signing-jobs output from the same account:

{
    "jobs": [
        {
            "jobId": "db882524-902e-4bd6-ac03-a66df08e73a0",
            "source": {
                "s3": {
                    "bucketName": "awscookbook505-src-pl42eg",
                    "key": "lambda_function.zip",
                    "version": "cbIsFsfeGezV8l6IkH2bDLhAAe_5sjgk"
                }
            },
            "signedObject": {
                "s3": {
                    "bucketName": "awscookbook505-dst-pl42eg",
                    "key": "signed-db882524-902e-4bd6-ac03-a66df08e73a0.zip"
                }
            },
            "signingMaterial": {},
            "createdAt": 1682719388,
            "status": "Succeeded",
            "isRevoked": true,
            "profileName": "AWSCookbook505_pl42eg",
            "profileVersion": "ELAcw04kNv",
            "platformId": "AWSLambda-SHA384-ECDSA",
            "platformDisplayName": "AWS Lambda",
            "signatureExpiresAt": 2037736988,
            "jobOwner": "430037344291",
            "jobInvoker": "430037344291"
        }
    ]
}

👍 👍 Two thumbs up from me!

Copy link
Member

@sstoops sstoops left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good to me now! Great job, Gaby!

@gsoria
Copy link
Author

gsoria commented May 1, 2023

Thanks for the review @sstoops @danarbaugh ❤️

@gsoria gsoria merged commit 0b661ad into oreilly-main May 1, 2023
@sstoops sstoops deleted the CL-522 branch May 24, 2023 19:35
@sstoops sstoops restored the CL-522 branch May 24, 2023 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants