synfinatic / aws-sso-cli

A powerful tool for using AWS Identity Center for the CLI and web console.
https://synfinatic.github.io/aws-sso-cli/
GNU General Public License v3.0
421 stars 50 forks source link

Documentation update showing how to use multiple accounts #815

Closed drmikecrowe closed 1 month ago

drmikecrowe commented 3 months ago

I don't understand how to utilize the cli tools to login in the following configuration. I have these key ignorances:

~/.aws-sso/config.yaml (partial)

SSOConfig:
  personal:
    SSORegion: us-east-x
    StartUrl: https://xxxxx.awsapps.com/start
    Accounts:
      'xxxxxxxxxxxx':
        Name: mike
    DefaultRegion: us-east-x
    AuthUrlAction: open
  pinnacle:
    SSORegion: us-east-x
    StartUrl: https://xxxxx.awsapps.com/start
    Accounts:
      'xxxxxxxxxxxx':
        Name: data
      'xxxxxxxxxxxx':
        Name: dev
...

~/.aws/config (partial)

[profile personal-mike-AdministratorAccess]
credential_process = aws-sso -u open -S "personal" process --arn arn:aws:iam::xxxxxxxxxxxx:role/AdministratorAccess
region = us-east-x

[profile pinnacle-data]
credential_process = aws-sso -u open -S "pinnacle" process --arn arn:aws:iam::xxxxxxxxxxxx:role/AWSAdministratorAccess
region = us-east-x

[profile pinnacle-dev]
credential_process = aws-sso -u open -S "pinnacle" process --arn arn:aws:iam::xxxxxxxxxxxx:role/AWSAdministratorAccess
region = us-east-x
...

Some of my tooling needs ~/.aws/credentials, so I wrote this script:

#!/usr/bin/env bash

aws-sso-creds() {
    printf "[%s]\n" $AWS_SSO_PROFILE
    printf "aws_access_key_id = %s\n" $AWS_ACCESS_KEY_ID
    printf "aws_secret_access_key = %s\n" $AWS_SECRET_ACCESS_KEY
    printf "aws_session_token = %s\n" $AWS_SESSION_TOKEN
}

rm -f ~/.aws/credentials
touch ~/.aws/credentials
aws-sso -S pinnacle eval --arn arn:aws:iam::xxxxxxxxxxxx:role/AWSAdministratorAccess > /tmp/.aws-sso-dev.sh
source /tmp/.aws-sso-dev.sh
aws-sso-creds >> ~/.aws/credentials
aws-sso -S pinnacle eval --arn :aws:iam::xxxxxxxxxxxx:role/AWSAdministratorAccess > /tmp/.aws-sso-data.sh
source /tmp/.aws-sso-data.sh
aws-sso-creds >> ~/.aws/credentials
aws-sso -S pinnacle eval --arn :aws:iam::xxxxxxxxxxxx:role/AWSAdministratorAccess > /tmp/.aws-sso-prod.sh
source /tmp/.aws-sso-prod.sh
aws-sso-creds >> ~/.aws/credentials
synfinatic commented 3 months ago

If your code really requires ~/.aws/credentials then it is broken and should be using the AWS SDK. Assuming your code is not actively broken, then it should support the profile config in ~/.aws/config which is generated thusly:

https://synfinatic.github.io/aws-sso-cli/commands/#config-profiles

drmikecrowe commented 1 month ago

In our case, we are running inside a docker container, so ~/.aws/credentials is the easiest vehicle to populate the credentials for multiple profiles that we use in Terraform. We specify the profile in our terraform setup to handle multiple environments (for example, state is globally stored in the root environment, RDS has to talk to both the current and root environment to delegate DNS, etc)

Additionally, I'm confused by

If your code really requires ~/.aws/credentials then it is broken

given aws documents its usage here. Can you help me understand a better workflow than using ~/.aws/credentials? Could we authenticate aws-sso-cli and then use the profile config you describe?

synfinatic commented 1 month ago

AWS SSO credentials are temporary. Credentials in ~/.aws/credentials are for static credentials. I don't support putting temporary credentials where static credentials go, because that prevents them from being rotated/updated as required. Also, the point of aws-sso is to be more secure than placing your secrets in clear text files.

Terraform doesn't require using ~/.aws/credentials because it uses the AWS Go SDK.

Honestly, it seems like what you really want to be doing is just using a single IAM Role/Permission Set that your user assumes. Then pass those IAM credentials into the docker container via environment variables. Then configure your terraform to use iam:AssumeRole to switch to the other accounts.

Alternatively, do as I originally suggested and make sure to add the aws-sso binary to the docker container.

drmikecrowe commented 1 month ago

Ah, I'm tracking now. What I was missing was the static vs. temporary nature of ~/.aws/credentials. I'm good now

drmikecrowe commented 1 month ago

OK, reopening this because installing within the docker container led to more questions/observations. Given Leapp is shutting down, this would be ideal for a replacement for our workflows that depended on it.

mkdir ~/.aws-sso
sed 's/open/print/g' /localhost/.aws-sso/config.yaml >~/.aws-sso/config.yaml
🐋  PSG/Geodesic [Docker] bsh ❯ aws-sso
Enter passphrase to unlock "/conf/.aws-sso/secure":

        Verify this code in your browser: RXST-WVKS
Please open the following URL in your browser:

https://device.sso.us-east-2.amazonaws.com/?user_code=RXST-WVKS

The following changes are proposed to /localhost/.aws/config:
--- /localhost/.aws/config
+++ /localhost/.aws/config.new
@@ -1,35 +1,27 @@
 # BEGIN_AWS_SSO_CLI
...
 # END_AWS_SSO_CLI

Modify /localhost/.aws/config with proposed changes?: No
List of AWS roles for SSO Instance: pinnacle [Expires in: 7h 57m]

AccountIdPad | AccountAlias        | RoleName                   | Profile                                 | Expires
===================================================================================================================
...

mcrowe in infrastructure on  remove-qbwc [#] with infrastructure took 2m30s
🐋  PSG/Geodesic [Docker] bsh ❯ aws-sso-profile pinnEnter passphrase to unlock "/conf/.aws-sso/secure": acle-dev
synfinatic commented 1 month ago

So looking deeper into this...

Fundamentally, the only way to use multiple IAM roles/profiles directly with Terraform is going to be via ~/.aws/credentials. There is a strong design pattern with AWS that a process/service should be granted a single IAM Role, and so that ties our hands. (EC2 and ECS metadata services for example both enforce this.) The exception for this is for you to use IAM role chaining which TF supports, but I'm assuming you've decided not to do for various reasons? The big advantage of using EC2/ECS/etc is that AWS auto-rotates the IAM credentials for you before they expire and they are always valid- for the life of the instance/container.

So with that in mind, the best solution right now I can think of really is basically what you did in your shell script by calling aws-sso eval and writing to a file which you then copy to your container as ~/.aws/credentials. Yes, the credentials will not auto-refresh when they expire. Not sure how long your TF apply is taking but you can increase your IAM credential lifetime up to a maximum of 12hrs.

In theory, you could gain a bit more time (hours) by utilizing the JSON secure store. You'd then authenticate via your SSO provider, copy the JSON store + config.yaml to the container and use the credential_process trick. Then as long as your SSO session has not expired, it will automatically refresh the IAM credentials. That said, your SSO session timer may or may not be longer than the IAM credential timer, so this might not really help.

To answer your other question... there is no "refresh all IAM tokens" option, but you can run aws-sso flush and then fetch new tokens via aws-sso eval. Of course, that only works if you have a valid SSO token/have previously logged in.

Anyways, due to the 2nd SSO timer, I'm not really sure how I can meaningfully improve your situation.

drmikecrowe commented 1 month ago

Actually, I have a working prototype using the credential_process! Turns out later versions of terraform support this, but after installing aws-sso-cli in docker, I had to jump thru some hoops. Here's how I advertised it:

image

I am interested in your opinion of this section:

aws-sso --no-config-check
for f in PROFILE1 PROFILE2 PROFILE3; do
    SHELL=/bin/bash aws-sso -L error --no-config-check eval -p $f > /dev/null
done
aws-sso list

From what I've been able to gleen:

  1. First aws-sso (no params) prompts the browser to authenticate
  2. The aws-sso eval in the loop actually retrieves creds for each profile. When I didn't have this, I was getting expired permission issues
  3. This simply shows all the statuses and isn't required
synfinatic commented 1 month ago
  1. I honestly don't understand what the context is for those commands. They're mostly right I guess?
  2. You could use the file / gpg based encryption + gpg-agent and have an obviously much more secure solution at the cost of complexity.
  3. Frankly, I'd just write the credentials out to the ~/.aws/credentials file and skip the use of credential_process if you're just going to use json since it is less complicated and will result in faster performance.
  4. Not sure I understand why you have to iterate over the profile(s) to get past the "expired permission issue" or what that is referring to.

Anyways, I don't use geodesic so I'm glad you got it to work. If it meets your needs I guess that's good enough. If someone from the geodesic team is looking to collaborate, I'm here.

drmikecrowe commented 1 month ago

OK, sorry, in my head this made perfect sense. Let me step back and give some context:

So, with that background, my design is essentially:

I tried to find something keyring compatible that would work inside docker (such as your gpg suggestion), but I finally gave up. The interim creds are stored inside the container, so when we exit the container, the startup script removes it. It's not ultra secure, but good enough in our case. Not every user uses gpg -- I considered initializing it locally inside, but didn't really spend any time on it.

Regarding:

Not sure I understand why you have to iterate over the profile(s) to get past the "expired permission issue" or what that is referring to.

You were right, I don't. Must have been operator error

synfinatic commented 1 month ago

When you say "~/.aws" is symlinked, you mean the files are copied at image build time or you are mounting it as a volume?

drmikecrowe commented 1 month ago

Mounting as a volume

Get Outlook for Androidhttps://aka.ms/AAb9ysg


From: Aaron Turner @.> Sent: Saturday, June 1, 2024 10:16:03 PM To: synfinatic/aws-sso-cli @.> Cc: drmikecrowe @.>; State change @.> Subject: Re: [synfinatic/aws-sso-cli] Documentation update showing how to use multiple accounts (Issue #815)

When you say "~/.aws" is symlinked, you mean the files are copied at image build time or you are mounting it as a volume?

— Reply to this email directly, view it on GitHubhttps://github.com/synfinatic/aws-sso-cli/issues/815#issuecomment-2143669351, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAAWBSFADIB4EP4LLIR6BATZFJ56HAVCNFSM6AAAAABFIZESBWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNBTGY3DSMZVGE. You are receiving this because you modified the open/close state.Message ID: @.***>

drmikecrowe commented 1 month ago

LMK if you want me to add this to the documentation somehow

synfinatic commented 1 month ago

Honestly, no. The use ofjson as the SecureStore is not something I would ever advocate anyone use. I honestly consider it a bug that it is documented so anyone but me knows it exists.