A frustrating limitation of the AWS Amplify platform: it can “plug straight in” to GitLab.com SaaS, but doesn’t have support for self managed yet. This issue is tracked https://github.com/aws-amplify/amplify-hosting/issues/14

Wanting to automate all of our deployments, I had to “find a way”.

It took far longer than it should have because I tripped up and went down a few rabbit holes, but here’s the final, simple, working solution. This assumes you have created the app in the AWS console and just want to be able to deploy new releases.

Create an AWS IAM user:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "amplify:StartDeployment",
            "Resource": "arn:aws:amplify:REGION:ACCOUNT_ID:apps/APP_ID/*"
        }
    ]
}

You will need to replace REGION, ACCOUNT_ID and APP_ID with the relevant values. You can also go further and limit to a specific branch if desired.

You may wish to grant your user less restrictive permission (for example, if you want the same credentials to be used to deploy multiple apps).

Configure GitLab CI/CD Variables:

I chose to configure: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION and set them to be protected and masked. You could also define your APP_ID and BRANCH_NAME here if you wanted to (instead we do it in the yaml below).

Configure .gitLab-ci.yml:

build:
  script:
    - apt-get update
    - apt-get install zip -y
    - echo "JOB_ID=$CI_JOB_ID" > build.env
    - npm run build
    - zip -r -j dist.zip dist 
  artifacts:
    paths:
      - dist.zip
    reports:
      dotenv: build.env

deploy:
  image: 
    name: amazon/aws-cli
    entrypoint: [""]
  variables:
    APP_ID: app_id
    BRANCH_NAME: branch_name
    SOURCE_URL: $CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$JOB_ID/artifacts/dist.zip?job=build&job_token=$CI_JOB_TOKEN
  script:
    - aws amplify start-deployment --app-id $APP_ID --branch-name $BRANCH_NAME --source-url $SOURCE_URL
  needs:
    - build

You will need to replace app_id and branch_name with the relevant values.

That’s it!

It’s fairly straightforward, but there’s a tiny bit of “magic”.

AWS Amplify requires a publicly accessible URL to download your project. We can achieve this by:

  • splitting the pipeline into multiple jobs
  • storing build artifacts and the build job id
  • using the $CI_JOB_TOKEN to authorize the “private” artifact download endpoint

Big shout to Marco and Niklas from the GitLab community for helping me debug/troubleshoot and get this working.

I would love to know if you have a better/simpler/easier method, feel free to share.

While developing this solution I had some issues with the AWS CLI:

root@a1b5517efdf2:/# aws amplify start-deployment --app-id abc123 --branch-name test --source-url "https://www.example.net/wp-content/uploads/2022/08/dist.zip"

Error parsing parameter '--source-url': Unable to retrieve https://www.example.net/wp-content/uploads/2022/08/dist.zip: 'utf-8' codec can't decode byte 0x9c in position 11: invalid start byte

My solution initially was to use the AWS Ruby SDK:

require 'aws-sdk-amplify'

amplify = Aws::Amplify::Client.new
amplify.start_deployment({
  app_id: ENV["APP_ID"],
  branch_name: ENV["BRANCH_NAME"],
  source_url: ENV["SOURCE_URL"],
})

There may be a scenario where you would prefer to use the SDK, so I felt it worth including this alternate approach.

It turned out I was using an old version of the CLI, and updating to the latest fixed the issue, allowing me to get rid of the custom Ruby solution.