Department | Accessible S3 Resources | Access Type |
---|---|---|
Marketing | s3://shopfast-data/products/ | Read |
s3://shopfast-data/feedback/ | Read | |
Sales | s3://shopfast-data/transactions/ | Read/Write |
s3://shopfast-data/users/ | Read/Write | |
Customer Support | s3://shopfast-data/users/ | Read |
s3://shopfast-data/feedback/ | Read/Write | |
Product Management | s3://shopfast-data/products/ | Read/Write |
s3://shopfast-internal/leads/ | Read | |
HR | s3://shopfast-internal/employee-records/ | Read/Write |
s3://shopfast-internal/benefits/ | Read/Write |
Run the following commands to deploy the terraform stack
terraform init
terraform apply
export AWS_DEFAULT_REGION=ap-southeast-2
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export AWS_ROLE_TO_ASSUME=arn:aws:iam::$AWS_ACCOUNT_ID:role/ShopFast-CustomerSupport
export SHOPFAST_DATA_BUCKET=$(terraform output -raw shopfast_data_bucket)
# Sets the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables
CREDENTIALS_JSON=$(aws sts assume-role --role-arn $AWS_ROLE_TO_ASSUME --role-session-name ShopFastRole)
export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SessionToken')
aws s3control get-data-access \
--account-id $AWS_ACCOUNT_ID \
--target s3://$SHOPFAST_DATA_BUCKET/users* \
--permission READWRITE \
--privilege Default
# An error occurred (AccessDenied) when calling the GetDataAccess operation: You do not have READWRITE permissions to the requested S3 Prefix: s3://terraform-20231210044558274900000002/users*
export AWS_DEFAULT_REGION=ap-southeast-2
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export AWS_ROLE_TO_ASSUME=arn:aws:iam::$AWS_ACCOUNT_ID:role/ShopFast-CustomerSupport
export SHOPFAST_DATA_BUCKET=$(terraform output -raw shopfast_data_bucket)
# Sets the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables
CREDENTIALS_JSON=$(aws sts assume-role --role-arn $AWS_ROLE_TO_ASSUME --role-session-name ShopFastRole)
export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SessionToken')
CREDENTIALS_JSON=$(aws s3control get-data-access \
--account-id $AWS_ACCOUNT_ID \
--target s3://$SHOPFAST_DATA_BUCKET/users* \
--permission READ \
--privilege Default)
# {
# "Credentials": {
# "AccessKeyId": "ASIAZZZZZZZZZZZZZZZZ",
# "SecretAccessKey": "RA+YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY",
# "SessionToken": "IQoJb3JpZ2luXXXXXXXXXXXXXXXXXXXXXXXXXX",
# "Expiration": "2023-12-06T16:16:19+00:00"
# },
# "MatchedGrantTarget": "s3://terraform-20231210044558274900000002/users*"
# }
export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SessionToken')
$ aws sts get-caller-identity
# {
# "UserId": "ASIAZZZZZZZZZZZZZZZZ:access-grants-ade86c3c-4781-4c65-8beb-4639bb72f5e6",
# "Account": "111111111111",
# "Arn": "arn:aws:sts::111111111111:assumed-role/terraform-20231210044558274900000002/access-grants-ade86c3c-4781-4c65-8beb-4639bb72f5e6"
# }
Get object
aws s3api get-object --bucket terraform-20231210044558274900000002 --key users/user_list user_list_downloaded
# {
# "AcceptRanges": "bytes",
# "LastModified": "2023-12-10T05:00:37+00:00",
# "ContentLength": 32,
# "ETag": "\"4aa99f977fb1e5ba4d846e408f6a90ba\"",
# "ContentType": "application/octet-stream",
# "ServerSideEncryption": "AES256",
# "Metadata": {}
# }
Note: To perform these steps, there must be an existing AWS IAM Identity Center (IIC) instance and a user (or group) in the directory. I won't be covering how to setup AWS IAM Identity Center (IIC) in this guide.
Create a new file terraform.tfvars
with the following content
sso_instance_id = "ssoins-XXXXXXXXXXXXX"
sso_grantee = {
"type": "DIRECTORY_USER",
"id": "97670ae0f2-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX"
}
Deploying these changes will link AWS S3 Access Grants to IAM Identity Center (IIC)
# Set AWS credentials for the S3 Access Grant account (111111111111 in the example)
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
export AWS_SESSION_TOKEN=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
terraform init
terraform apply
Export some variables while you are still authenticated with the S3 Access grant account (used for terraform deploy)
echo "export SHOPFAST_DATA_BUCKET=$(terraform output -raw shopfast_data_bucket)" >> federation/.env
echo "export AWS_S3_ACCESS_GRANT_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)" >> federation/.env
echo "export AWS_S3_ACCESS_GRANT_ROLE_ARN=$(terraform output -raw identity_bearer_iam_role_arn)" >> federation/.env
echo "export AWS_S3_ACCESS_GRANT_CLIENT_APP_ROLE_ARN=$(terraform output -raw client_application_iam_role_arn)" >> federation/.env
!!! The following steps must be done while authenticated with the AWS IAM Identity Center (IIC) account. !!!
# Set AWS credentials for the AWS IAM Identity Center (IIC) account (222222222222 in the example)
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
export AWS_SESSION_TOKEN=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
cd federation
terraform init
terraform apply
There are a few steps that do not have terraform resources, so they must be done manually - Start by exporting some variables
echo "export AWS_IIC_APPLICATION_ARN=$(terraform output -raw s3_access_grants_application_arn)" >> .env
echo "export AWS_IIC_TRUSTED_ISSUER_ARN=$(terraform output -raw s3_access_grants_trusted_token_issuer_arn)" >> .env
Then source all the variables into your shell environment.
source .env
Create an application grant for the application
export AWS_IIC_APPLICATION_AUTHORIZED_AUDIENCE="8943e428-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
GRANT_JSON=$(jq --arg issuer_arn "$AWS_IIC_TRUSTED_ISSUER_ARN" \
--arg audience "$AWS_IIC_APPLICATION_AUTHORIZED_AUDIENCE" \
'.JwtBearer.AuthorizedTokenIssuers[0].TrustedTokenIssuerArn = $issuer_arn |
.JwtBearer.AuthorizedTokenIssuers[0].AuthorizedAudiences[0] = $audience' \
templates/grant.json)
aws sso-admin put-application-grant \
--application-arn $AWS_IIC_APPLICATION_ARN \
--grant-type "urn:ietf:params:oauth:grant-type:jwt-bearer" \
--grant "$GRANT_JSON"
Create an application authentication method for the application
AUTHENTICATION_METHOD_JSON=$(jq \
--arg app_arn "$AWS_IIC_APPLICATION_ARN" \
--arg role_arn "$AWS_S3_ACCESS_GRANT_CLIENT_APP_ROLE_ARN" \
--arg aws_id "$AWS_S3_ACCESS_GRANT_ACCOUNT_ID" \
'.Iam.ActorPolicy.Statement[0].Principal.AWS = $aws_id |
.Iam.ActorPolicy.Statement[0].Resource = $app_arn |
.Iam.ActorPolicy.Statement[0].Condition.ArnEquals["aws:PrincipalArn"] = $role_arn' \
templates/authentication-method.json)
aws sso-admin put-application-authentication-method \
--application-arn $AWS_IIC_APPLICATION_ARN \
--authentication-method-type IAM \
--authentication-method "$AUTHENTICATION_METHOD_JSON"
Generate the .env
file in the federation/web
folder that will be used by the client application
cat <<EOF > web/.env
FLASK_SECRET_KEY=Your_Secret_Key
AWS_IIC_APPLICATION_ARN=${AWS_IIC_APPLICATION_ARN}
AWS_S3_ACCESS_GRANT_ROLE_ARN=${AWS_S3_ACCESS_GRANT_ROLE_ARN}
AWS_S3_ACCESS_GRANT_ACCOUNT_ID=${AWS_S3_ACCESS_GRANT_ACCOUNT_ID}
AWS_TARGET_BUCKET_NAME=${SHOPFAST_DATA_BUCKET}
EOF
Setup the client application dependencies
cd federation/web
# Install dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Create a copy of client_secrets.json.example
and rename it to client_secrets.json
. Update the client_id
and client_secret
with values from your IDP (in our case, JumpCloud).
cp client_secrets.json.example client_secrets.json
Setup credentials then run the client application
# Set AWS credentials for the S3 Access Grant account (111111111111 in the example)
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
export AWS_SESSION_TOKEN=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
# Assume the S3 Access Grant role
CREDENTIALS_JSON=$(aws sts assume-role --role-arn $AWS_S3_ACCESS_GRANT_CLIENT_APP_ROLE_ARN --role-session-name s3-access-grants)
export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDENTIALS_JSON | jq -r '.Credentials.SessionToken')
# Run the client application
python3 jumpcloud.py
Login at http://localhost:5000/login, then navigate to http://localhost:5000/get-s3-data to view the data.
Remove AWS IAM Identity Center configuration
# Set AWS credentials for the AWS IAM Identity Center (IIC) account (222222222222 in the example)
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
export AWS_SESSION_TOKEN=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
cd federation
terraform init
terraform destroy
Remove AWS S3 Access Grants configuration
# Set AWS credentials for the S3 Access Grant account (111111111111 in the example)
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
export AWS_SESSION_TOKEN=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
cd ..
terraform init
terraform destroy