diff --git a/.github/workflows/signing_test.yaml b/.github/workflows/signing_test.yaml new file mode 100644 index 00000000..d888652d --- /dev/null +++ b/.github/workflows/signing_test.yaml @@ -0,0 +1,202 @@ +name: "signing-test" + +on: + workflow_dispatch: + inputs: + ref: + description: "Branch, tag, or commit SHA to check out" + required: true + default: "feature/ELI-702-code-signing" + artifact_tag: + description: "Artifact tag to deploy, for example dev-20260410120000" + required: true + artifact_run_id: + description: "Workflow run ID that produced the lambda artifact" + required: true + +concurrency: + group: test-deployments + cancel-in-progress: false + +permissions: + contents: read + id-token: write + actions: read + +jobs: + metadata: + name: "Resolve metadata" + runs-on: ubuntu-latest + outputs: + terraform_version: ${{ steps.vars.outputs.terraform_version }} + tag: ${{ steps.tag.outputs.name }} + steps: + - name: "Checkout selected ref" + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} + + - name: "Set CI/CD variables" + id: vars + run: | + echo "terraform_version=$(grep '^terraform' .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT + + - name: "Use provided artifact tag" + id: tag + run: | + echo "name=${{ inputs.artifact_tag }}" >> $GITHUB_OUTPUT + echo "Resolved tag: ${{ inputs.artifact_tag }}" + + sign-lambda-artifact: + name: "Sign lambda artifact for TEST" + runs-on: ubuntu-latest + needs: [metadata] + environment: test + timeout-minutes: 45 + permissions: + id-token: write + contents: read + outputs: + bucket_name: ${{ steps.tf_output.outputs.bucket_name }} + steps: + - name: "Checkout selected ref" + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} + + - name: "Setup Terraform" + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: ${{ needs.metadata.outputs.terraform_version }} + + - name: "Configure AWS Credentials" + uses: aws-actions/configure-aws-credentials@v6 + with: + role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role + aws-region: eu-west-2 + + - name: "Download lambda artefact from chosen workflow run" + uses: actions/download-artifact@v7 + with: + name: lambda-${{ needs.metadata.outputs.tag }} + path: ./dist + run-id: ${{ inputs.artifact_run_id }} + github-token: ${{ github.token }} + + - name: "Terraform Init (TEST api-layer)" + env: + ENVIRONMENT: test + WORKSPACE: "default" + run: | + echo "Running: make terraform env=$ENVIRONMENT workspace=$WORKSPACE stack=api-layer tf-command=init" + make terraform env=$ENVIRONMENT stack=api-layer tf-command=init workspace=$WORKSPACE + working-directory: ./infrastructure + + - name: "Extract Terraform outputs" + id: tf_output + run: | + BUCKET=$(terraform output -raw lambda_artifact_bucket) + PROFILE=$(terraform output -raw lambda_signing_profile_name) + echo "bucket_name=$BUCKET" >> $GITHUB_OUTPUT + echo "signing_profile_name=$PROFILE" >> $GITHUB_OUTPUT + working-directory: ./infrastructure/stacks/api-layer + + - name: "Upload unsigned lambda artifact to S3" + run: | + aws s3 cp ./dist/lambda.zip \ + s3://${{ steps.tf_output.outputs.bucket_name }}/artifacts/${{ needs.metadata.outputs.tag }}/lambda.zip \ + --region eu-west-2 + + - name: "Get uploaded source object version" + id: source_object + run: | + VERSION_ID=$(aws s3api head-object \ + --bucket "${{ steps.tf_output.outputs.bucket_name }}" \ + --key "artifacts/${{ needs.metadata.outputs.tag }}/lambda.zip" \ + --query 'VersionId' \ + --output text \ + --region eu-west-2) + echo "version_id=$VERSION_ID" >> $GITHUB_OUTPUT + + - name: "Start signing job" + id: signing + env: + SIGNING_PROFILE_NAME: ${{ steps.tf_output.outputs.signing_profile_name }} + run: | + JOB_ID=$(aws signer start-signing-job \ + --source "s3={bucketName=${{ steps.tf_output.outputs.bucket_name }},key=artifacts/${{ needs.metadata.outputs.tag }}/lambda.zip,version=${{ steps.source_object.outputs.version_id }}}" \ + --destination "s3={bucketName=${{ steps.tf_output.outputs.bucket_name }},prefix=signed-artifacts/${{ needs.metadata.outputs.tag }}/}" \ + --profile-name "$SIGNING_PROFILE_NAME" \ + --query 'jobId' \ + --output text \ + --region eu-west-2) + echo "job_id=$JOB_ID" >> $GITHUB_OUTPUT + + - name: "Wait for signing job" + run: | + aws signer wait successful-signing-job \ + --job-id "${{ steps.signing.outputs.job_id }}" \ + --region eu-west-2 + + - name: "Resolve signed artifact location" + id: signed_object + run: | + SIGNED_BUCKET=$(aws signer describe-signing-job \ + --job-id "${{ steps.signing.outputs.job_id }}" \ + --region eu-west-2 \ + --query 'signedObject.s3.bucketName' \ + --output text) + + SIGNED_KEY=$(aws signer describe-signing-job \ + --job-id "${{ steps.signing.outputs.job_id }}" \ + --region eu-west-2 \ + --query 'signedObject.s3.key' \ + --output text) + + echo "bucket_name=$SIGNED_BUCKET" >> $GITHUB_OUTPUT + echo "object_key=$SIGNED_KEY" >> $GITHUB_OUTPUT + + - name: "Download signed lambda artifact" + run: | + aws s3 cp \ + "s3://${{ steps.signed_object.outputs.bucket_name }}/${{ steps.signed_object.outputs.object_key }}" \ + ./dist/lambda.zip \ + --region eu-west-2 + + - name: "Upload signed lambda artifact for current workflow" + uses: actions/upload-artifact@v6 + with: + name: lambda-${{ needs.metadata.outputs.tag }} + path: ./dist/lambda.zip + + deploy: + name: "Deploy to TEST (approval required)" + runs-on: ubuntu-latest + needs: [metadata, sign-lambda-artifact] + environment: test + timeout-minutes: 10080 + permissions: + id-token: write + contents: read + steps: + - name: "Checkout selected ref" + uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} + + - name: "Setup Terraform" + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: ${{ needs.metadata.outputs.terraform_version }} + + - name: "Download signed lambda artefact" + uses: actions/download-artifact@v7 + with: + name: lambda-${{ needs.metadata.outputs.tag }} + path: ./dist + + - name: "Configure AWS Credentials" + uses: aws-actions/configure-aws-credentials@v6 + with: + role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role + aws-region: eu-west-2 diff --git a/infrastructure/modules/lambda/lambda.tf b/infrastructure/modules/lambda/lambda.tf index db67f93a..01fb4256 100644 --- a/infrastructure/modules/lambda/lambda.tf +++ b/infrastructure/modules/lambda/lambda.tf @@ -1,7 +1,6 @@ resource "aws_lambda_function" "eligibility_signposting_lambda" { #checkov:skip=CKV_AWS_116: No deadletter queue is configured for this Lambda function, as the requests are synchronous #checkov:skip=CKV_AWS_115: Concurrent execution limit will be set at APIM level, not at Lambda level - #checkov:skip=CKV_AWS_272: Skipping code signing but flagged to create ticket to investigate on ELI-238 # If the file is not in the current working directory you will need to include a # path.module in the filename. filename = var.file_name @@ -11,6 +10,8 @@ resource "aws_lambda_function" "eligibility_signposting_lambda" { source_code_hash = filebase64sha256(var.file_name) + code_signing_config_arn = local.enable_lambda_code_signing ? aws_lambda_code_signing_config.signing_config.arn : null + runtime = var.runtime timeout = 30 memory_size = 2048 diff --git a/infrastructure/modules/lambda/locals.tf b/infrastructure/modules/lambda/locals.tf new file mode 100644 index 00000000..12044817 --- /dev/null +++ b/infrastructure/modules/lambda/locals.tf @@ -0,0 +1,5 @@ +locals { + enable_lambda_code_signing = false + # enable_lambda_code_signing = contains(["test", "preprod", "prod"], var.environment) + # For the next deployment ^ +}