amazon-web-servicesgithub-actions

GitHub actions- EC2 Github self-hosted runner does not have assigned "env" field in its runtime


I've set up the following Github action:

name: Fulfill Terraform Production

on:
    workflow_dispatch:
    push:
        branches:
            - main
        paths:
            - terraform/**
            - packer/**
            - src/**

concurrency:
    group: ${{ github.workflow }}
    cancel-in-progress: false

jobs:
    fulfill_pre_required_terraform:
        name: Fulfill Pre-Required Terraform Production
        runs-on: ubuntu-latest
        outputs:
          github-runner-label: ${{ steps.start-ec2-github-runner.outputs.label }}
          github-runner-ec2-instance-id: ${{ steps.start-ec2-github-runner.outputs.ec2-instance-id }}
          database-url: ${{ steps.terraform-pre-required-outputs.outputs.DATABASE_URL}}
        env:
            AWS_REGION: ${{ vars.AWS_REGION }}
            AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
            AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
            TF_VAR_aws_region: ${{ vars.AWS_REGION }}
            TF_VAR_smartabook_route53_zone_id: ${{ secrets.SMARTABOOK_ROUTE53_ZOND_ID }}
            TF_VAR_smartabook_backend_ecr_repository_name: smartabook-backend
            TF_VAR_smartabook_database_username: ${{ secrets.SMARTABOOK_DATABASE_USERNAME }}
            TF_VAR_smartabook_database_password: ${{ secrets.SMARTABOOK_DATABASE_PASSWORD }}
            TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET }}
            TF_VAR_salt: ${{ secrets.SALT }}
            TF_VAR_sendgrid_api_key: ${{ secrets.SENDGRID_API_KEY }}
            TF_VAR_sendgrid_from_email: ${{ secrets.SENDGRID_FROM_EMAIL }}
            TF_VAR_sendgrid_from_name: ${{ secrets.SENDGRID_FROM_NAME }}
            TF_VAR_admin_secret: ${{ secrets.ADMIN_SECRET }}

        steps:
            - uses: actions/checkout@v4

            - name: Configure AWS credentials
              uses: aws-actions/configure-aws-credentials@v4
              with:
                  aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
                  aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
                  aws-region: ${{ vars.AWS_REGION }}

            - name: Check if GitHub runner AMI already exists
              id: get-github-runner-ami-id
              env:
                GH_RUNNER_AMI_NAME: ${{ vars.GH_RUNNER_AMI_NAME}}
              run: |
                EXISTING_AMI_ID=$(aws ec2 describe-images \
                  --region ${{ vars.AWS_REGION }} \
                  --owners self \
                  --filters "Name=name,Values=$GH_RUNNER_AMI_NAME" \
                  --query 'Images[0].ImageId' \
                  --output text 2>/dev/null)

                echo "Got AMI ID output: $EXISTING_AMI_ID"

                echo "GH_RUNNER_AMI_ID=$EXISTING_AMI_ID" >> $GITHUB_OUTPUT

            - name: Terraform setup
              uses: hashicorp/setup-terraform@v3
              with:
                  terraform_wrapper: false

            - name: Terraform init
              working-directory: terraform/prod
              env:
                  TERRAFORM_REMOTE_BACKEND_S3_BUCKET_NAME: ${{ secrets.TERRAFORM_REMOTE_BACKEND_S3_BUCKET_NAME }}
              run: |
                  terraform init \
                  -backend-config="bucket=$TERRAFORM_REMOTE_BACKEND_S3_BUCKET_NAME" \
                  -backend-config="region=$AWS_REGION"

            - name: Terraform plan pre-required resources only
              working-directory: terraform/prod
              run: |
                  terraform plan -no-color -out pre_required.tfplan -target=module.backend_cluster.aws_ecr_repository.server -target=aws_db_instance.postgres

            - name: Terraform apply pre-required resources only
              working-directory: terraform/prod
              run: |
                  terraform apply pre_required.tfplan

            - name: Get Terraform pre-required outputs
              id: terraform-pre-required-outputs
              working-directory: terraform/prod
              run: |
                  github_runner_subnet_id=$(terraform output -raw github_runner_subnet_id)
                  github_runner_security_group_id=$(terraform output -raw github_runner_security_group_id)
                  database_url=$(terraform output -raw database_url)

                  echo "GITHUB_RUNNER_SUBNET_ID=$github_runner_subnet_id" >> $GITHUB_OUTPUT
                  echo "GITHUB_RUNNER_SECURITY_GROUP_ID=$github_runner_security_group_id" >> $GITHUB_OUTPUT
                  echo "DATABASE_URL=$database_url" >> $GITHUB_OUTPUT

            - name: Start EC2 GitHub runner
              id: start-ec2-github-runner
              uses: machulav/ec2-github-runner@v2
              with:
                  mode: start
                  github-token: ${{ secrets.EC2_GITHUB_RUNNER_CREATION_GITHUB_TOKEN }}
                  ec2-image-id: ${{ steps.build-github-runner-ami.outputs.GH_RUNNER_AMI_ID || steps.get-github-runner-ami-id.outputs.GH_RUNNER_AMI_ID }}
                  ec2-instance-type: t3.xlarge
                  subnet-id: ${{ steps.terraform-pre-required-outputs.outputs.GITHUB_RUNNER_SUBNET_ID }}
                  security-group-id: ${{ steps.terraform-pre-required-outputs.outputs.GITHUB_RUNNER_SECURITY_GROUP_ID }}

    fulfill_terraform:
      name: Fulfill Terraform Production
      needs: fulfill_pre_required_terraform
      runs-on: ${{ needs.fulfill_pre_required_terraform.outputs.github-runner-label }}
      continue-on-error: true
      env:
        AWS_REGION: ${{ vars.AWS_REGION }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        TF_VAR_aws_region: ${{ vars.AWS_REGION }}
        TF_VAR_smartabook_route53_zone_id: ${{ secrets.SMARTABOOK_ROUTE53_ZOND_ID }}
        TF_VAR_smartabook_backend_ecr_repository_name: smartabook-backend
        TF_VAR_smartabook_database_username: ${{ secrets.SMARTABOOK_DATABASE_USERNAME }}
        TF_VAR_smartabook_database_password: ${{ secrets.SMARTABOOK_DATABASE_PASSWORD }}
        TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET }}
        TF_VAR_salt: ${{ secrets.SALT }}
        TF_VAR_sendgrid_api_key: ${{ secrets.SENDGRID_API_KEY }}
        TF_VAR_sendgrid_from_email: ${{ secrets.SENDGRID_FROM_EMAIL }}
        TF_VAR_sendgrid_from_name: ${{ secrets.SENDGRID_FROM_NAME }}
        TF_VAR_admin_secret: ${{ secrets.ADMIN_SECRET }}
        DATABASE_URL: ${{ needs.fulfill_pre_required_terraform.outputs.database-url }}
      
      steps:
        - uses: actions/checkout@v4

        - name: Login to Amazon ECR
          id: login-ecr
          uses: aws-actions/amazon-ecr-login@v2

        - name: Get package.json version
          id: package-version
          run: echo "current_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT

        - name: Build, tag, and push image of website to Amazon ECR
          env:
              ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
              IMAGE_TAG: ${{ steps.package-version.outputs.current_version }}-${{ github.sha }}
          run: |
              docker build -t $ECR_REGISTRY/$TF_VAR_smartabook_backend_ecr_repository_name:$IMAGE_TAG -f ./Dockerfile --build-arg DATABASE_URL=$DATABASE_URL .
              docker push $ECR_REGISTRY/$TF_VAR_smartabook_backend_ecr_repository_name:$IMAGE_TAG

In the "fulfill_terraform", when trying to use $DATABASE_URL (as you can see in step name: Build, tag, and push image of website to Amazon ECR), this environment variable value is empty. I can guarantee that in job fulfill_pre_required_terraform, in step name: Get Terraform pre-required outputs, this command: echo "DATABASE_URL=$database_url" >> $GITHUB_OUTPUT works. I checked it and printed (echo) the value of $database_url and the value was non-empty but actual database URL.

Note that the job fulfill_terraform runs on self hosted runner, in comparison to fulfill_pre_required_terraform which runs on ubuntu-latest of GitHub. This makes me think that this is the issue.

Is there a way to resolve this issue easily? I can only think this solution:

  1. In the first job, upsert the value of DATABASE_URL to AWS secret manager
  2. In the second job, pull the value of DATABASE_URL from AWS secret manager

But I'm trying to ensure there is no other easy fix for this..


Solution

  • The issue is that GitHub probably skipped your database-url output because it contains sensitive value. You simply need to add:

    echo "::add-mask::$database_url"
    

    Before your output to $GITHUB_OUTPUT command

    See full example here