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

Support cross-account deploys #41

Closed
lucasnad27 opened this issue Oct 1, 2019 · 4 comments
Closed

Support cross-account deploys #41

lucasnad27 opened this issue Oct 1, 2019 · 4 comments
Assignees
Labels
enhancement New feature or request ignore_sla

Comments

@lucasnad27
Copy link

Problem

I'm using another aws orb that enables me to assume another role with my circleci aws user. However, I was unable to deploy across multiple aws accounts, utilizing cross account roles with this orb.

Proposed fix

Explicitly set the profile for all aws ecs commands and add an optional parameter called profile-name (similar to the aws-cli orb) as a parameter, with a default of...default

I have a fork that I'd be happy to submit as a pull request if there is some consensus on this being the best way to fix this issue.

Steps to reproduce bug

I was able to track this issue down to the aws cli (read: appears to be an aws cli bug, not a bug in this orb). If you create an aws session token, (which is necessary to assume a cross account role) aws commands don't seem to respect this setting unless you explicitly set your profile, even if it is the default. It has the downstream effect of rendering cross account deploys impossible with this orb.

Unfortunately, I was only able to reproduce this on a circleci machine, using the ssh feature. I was unable to reproduce on my local machine.

Here's the simplest way to reproduce within a circleci session

Push an update to a circleci project using this snippet of config:

    steps:
      - run:
          name: Setup common environment variables
          command: |
            echo 'export ENVIRONMENT="<< parameters.env >>"' >> $BASH_ENV
            echo 'export AWS_REGION="<< parameters.aws-region >>"' >> $BASH_ENV
            echo 'export ECS_CLUSTER_NAME="<< parameters.env >>"' >> $BASH_ENV
            echo 'export ECS_SERVICE_NAME="<< parameters.env >>-api"' >> $BASH_ENV
            echo 'export ECS_TASK_NAME="<< parameters.env >>-api"' >> $BASH_ENV
            echo 'export FULL_IMAGE_NAME="${AWS_ACCOUNT_ID}.dkr.ecr.<< parameters.aws-region >>.amazonaws.com/hostcompliance/${AWS_RESOURCE_NAME_PREFIX}:${CIRCLE_SHA1}"' >> $BASH_ENV
      - aws-cli/install
      - run: |
          aws configure set aws_access_key_id ${AWS_ACCESS_KEY} && \
          aws configure set aws_secret_access_key ${AWS_SECRET_ACCESS_KEY} && \
          aws iam get-user
      - run: |
          temp_role=$(aws sts assume-role --role-arn "arn:aws:iam::<< parameters.customer-account-id >>:role/DeployFargate" --role-session-name "RoleSession1") && \
          aws configure set aws_access_key_id $(echo $temp_role | jq .Credentials.AccessKeyId | xargs) && \
          aws configure set aws_secret_access_key $(echo $temp_role | jq .Credentials.SecretAccessKey | xargs) && \
          aws configure set aws_session_token $(echo $temp_role | jq .Credentials.SessionToken | xargs)
      - run:
          name: Set default region
          command: |
            aws configure set default.region << parameters.aws-region >>
      - update-service:
          family: "${ECS_TASK_NAME}"
          cluster-name: "${ECS_CLUSTER_NAME}"
          service-name: "${ECS_SERVICE_NAME}"
          container-image-name-updates: "container=${ECS_SERVICE_NAME},image-and-tag=${FULL_IMAGE_NAME}"
          container-env-var-updates: "container=${ECS_SERVICE_NAME},name=ENV,value=${ENVIRONMENT},container=${ECS_SERVICE_NAME},name=AWS_REGION,value=<< parameters.aws-region >>,container=${ECS_SERVICE_NAME},name=VERSION_INFO,value=${CIRCLE_SHA1}_${CIRCLE_BUILD_NUM},container=${ECS_SERVICE_NAME},name=BUILD_DATE,value=\"$(date)\""
          verify-revision-is-deployed: true

This will fail because a task definition doesn't exist. If you ssh to the box, you can try the following:

aws ecs describe-task-definition --task-definition production-api --include TAGS
returns
An error occurred (ClientException) when calling the DescribeTaskDefinition operation: Unable to describe task definition.

aws ecs describe-task-definition --task-definition production-api --include TAGS --profile default
returns

{
    "taskDefinition": {
    ...
    }
}

The crux of the problem here is that by default, the aws cli within a circleci machine is not assuming the cross account role unless you specify the profile in each call.

aws iam get-user yields...

{
    "User": {
        "Path": "/",
        "UserName": "circle-ci-read-only",
        "UserId": "<access key>",
        "Arn": "arn:aws:iam::<primary-account-id>:user/circle-ci-read-only",
        "CreateDate": "2018-10-09T05:48:53Z"
    }
}

where as aws iam get-user --profile default yields a 403 (because my cross account role doesn't have that privilege

An error occurred (AccessDenied) when calling the GetUser operation: User: arn:aws:sts::<customer-account-id>:assumed-role/DeployFargate/RoleSession1 is not authorized to perform: iam:GetUser on resource: user RoleSession1
@lokst
Copy link
Contributor

lokst commented Oct 6, 2019

@lucasnad27 Thank you so much for explaining this issue in such detail. Your solution sounds good and also potentially useful in other use cases. I'd love to receive your PR!

@lucasnad27
Copy link
Author

Glad to hear. I hope to have one ready for review by the end of this week.

@Shikkic
Copy link

Shikkic commented Apr 29, 2020

Hey all, I ran into this issue myself today and saw this issue/PR and was wondering if there were any plans to build this support out for the ECS orb?

I was able to get around it by doing a weird hack based on what @lucasnad27 was doing. Basically just overriding aws cred envs with generated ones before the update service step (The BASH_ENV stuff is CCI specific, thought I'd post in case this is helpful to anyone):

temp_role=$(aws sts assume-role --role-arn $AWS_DEPLOYMENT_ROLE_ARN --role-session-name "role_session")
echo "export AWS_ACCESS_KEY_ID=$(echo $temp_role | jq .Credentials.AccessKeyId | xargs)" >> $BASH_ENV; source $BASH_ENV;
echo "export AWS_SECRET_ACCESS_KEY=$(echo $temp_role | jq .Credentials.SecretAccessKey | xargs)" >> $BASH_ENV; source $BASH_ENV;
echo "export AWS_SESSION_TOKEN=$(echo $temp_role | jq .Credentials.SessionToken | xargs)" >> $BASH_ENV; source $BASH_ENV;

@brivu brivu assigned brivu and unassigned lokst May 20, 2022
@brivu
Copy link
Contributor

brivu commented May 20, 2022

This has been addressed in PR #153

@brivu brivu closed this as completed May 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request ignore_sla
Projects
None yet
Development

No branches or pull requests

4 participants