|
Bypassing the GitLab vs GitHub or GitLab vs AWS Code Pipeline debates, this article will focus on logistics of connecting GitLab that acts as CI/CD and deploys to AWS. One way to achieve this is to add AWS access keys as variables on GitLab, while this works it’s not a recommended practice from security perspective. It’s beyond the scope of the article to expand on this, I would just add that the accounts/roles that are needed for AWS deployment are typically quite powerful and should they get compromised, damage is likely to be extensive. The recommended option is to connect AWS with GitLab using the OpenID protocol. With this setup, GitLab acts as both an OpenID Authenticator and initiator of the authentication commands. AWS is then configured to trust GitLab as Authenticator for a specific role, guarded by three aspects:
There are generally 5 steps in getting this setup configured and I would recommend you take a deep breath and allocate a good portion of a day to get through them. Step 1. Optional in practice, but appears crucial from reading relevant articles is to establish ClientId or Audience. To start I would highly recommend you read this AWS article, while it’s misleading about a couple of points, namely that “ you must register your application with the IdP to receive a client ID.” and that /.well-known/openid-configuration must support id_token, it’s generally a well article that gives you a good overview of the process. If you want to go ahead with creation of ClientID, you can do so by logging on to your gitlab instance, then going to your group level, then Settings->Application and create a new application. The one confusing point you’ll encounter is entering a value of a callback url, feel free to enter https://localhost as it will not be used. Reference document from GitLab can be found here. https://docs.gitlab.com/ee/integration/oauth_provider.html Step 2: Add new Identity Provider on AWS IAM. I would refer you back to the article reference in Step 1 as it provides a reasonable description of the process. A few points on this doc is (Step 1 as before is optional) and if you skip it, then for step 6( Audience) you can just add any value, it’s simply there to create a placeholder policy that you will then edit via json. Step 3: Finish setting up AWS role. With step 2, you created an AWS Role, but that role relies on Audience which with GitLab is not much more secure than storing AWS Access Keys as GitLab variables. To secure it further you should restrict access to particular group, projects or branches. I would refer you to this article on gitlab to learn more. Below is a sample AWS Role setup you will end up with. If you setup clientid/audience in Step 1, you can keep it using the template below or you can simply skip it. In below example, client id is, group is ‘superproj’ hosted on gitlab.com and all repos and branches within the group can assume AWS role. "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "gitlab.com:aud": "My Favorite Client" }, "StringLike": { "gitlab.com:sub": "project_path:superpoj/*:ref_type:branch:ref:*" } } Step 4: Getting your .gitlab-ci.yml setup. The https://docs.gitlab.com/ee/ci/cloud_services/aws/ offer an example for setting up the pipeline, but I found a few issues with it.
I found the below template to work for me. jq is included in the aws base image, but if you need to add it to your image it’s not a big deal as well. image: public.ecr.aws/sam/build-python3.11 id_tokens: GITLAB_OIDC_TOKEN: aud: “My My Favorite Client” variables: ROLE_ARN: "arn:aws:iam::<your account>:role/<NameOfYourRole>" script: - CREDS=$(aws sts assume-role-with-web-identity --role-arn ${ROLE_ARN} --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}" --web-identity-token ${GITLAB_OIDC_TOKEN} --duration-seconds 3600 --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' --output json) - export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.[0]') - export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.[1]') - export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.[2]') Step 5: Is to add required permissions to your AWS role, this is something that I am still working through, but the entitlements required are extensive. Is this better than storing AWS Keys in GitLab? Not if you are just using aud that can be overridden in your pipeline. I would recommend restricting your role further to only the protected deployment branch and make sure that only people who you want to empower to make use of the powerful AWS deployment role are allowed to merge into the deployment branch. Then there is also a question of security of the gitlab server and user access to gitlab servers, but that feels like a risk on the level of securing access to AWS. At that level you should be concerned about protecting sensitive data with encryption and perhaps less concerned about costs of people spinning up unexpected AWS resources on your tab or even bringing down your application that you should be able to recover from backups. | |