Securely access AWS Secrets Manager across different AWS accounts
As the use-case of multi-account setup is being utilised in almost every architecture. We often come across the challenge to manage all the secrets in single AWS account (security account) and other account will fetch the secrets from parent account. Since creating redundant secret in each account will incur lot of cost and difficult to manage and migrate.
To simplify the problem, below are the 2 effective strategies to securely access secrets from one AWS account to other AWS accounts.
Approach 1: Using Assume Role
As per the above illustration, Security AWS account (ID:123) is the account where secrets are centrally stored. To access the secrets from Consumer AWS account (ID: 987) we will need to perform following steps:
- Create Policy Read_Custom_Secret in Security AWS account.
a. Sign in to Security AWS Account as admin. Open the IAM console
b. In the navigation pane on the left, choose Policies and then choose Create policy.
c. Select secrets manager service and provision required access using Visual Editor or use JSON tab to copy paste below policy while replacing account id with Security AWS account id and region with region_id where secrets were created. (Modify region_id, account id accordingly as highlighted in bold)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadFromSecret",
"Effect": "Allow",
"Action": [
"secretsmanager:ListSecrets",
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecretVersionIds"
],
"Resource": "arn:aws:secretsmanager:<region_id>:<account_id-123>:secret:*"
}
]
}
2. Create Role Read_Secret_Role in Security AWS account.
a. In the navigation pane on the left, choose Roles and then choose Create Role.
b. Choose Another AWS account in trusted entity. Add Consumer AWS account Id (987 for this instance) in Account ID section.Do not check on both optioned as mentioned below.
c. Click on Next:Permission, search and select the policy and click on Next:Tags. Add any tags if required then click on Next:Review.
d. Mention Role name, Role description and Click on Create role
3. Switch to Consumer AWS Account, and create new policy Consumer_Policy
a. Sign in to Consumer AWS Account as admin. Open the IAM console
b. In the navigation pane on the left, choose Policies and then choose Create policy.
c. Select JSON tab and copy paste below policy while replacing account id with Security AWS account id. (Modify account id accordingly as highlighted in bold)
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<account_id-123>:role/Read_Secret_Role"
}
}
d. Attach above policy to any role of instance, user as per requirement.
Through AssumeRole, temporary AWS credentials will be generated which can be used to fetch the secret value from Security AWS account.
Python code to validate and fetch secret from Security AWS account
import boto3
client = boto3.client('sts')
assumed_role_object = client.assume_role(
RoleArn='arn:aws:iam::<account_id-123>:role/Read_Secret_Role',
RoleSessionName='AssumeRoleSession'
)
credentials=assumed_role_object['Credentials']
client=boto3.client(
'secretsmanager',
region_name='us-east-1',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'],
)
get_secret_value_response = client.get_secret_value(SecretId='secret_name')
get_secret_value_response['SecretString']
Before running the above code ensure the policy created in Step 3 is attached to the role or user.
Approach 2: Using Resource Based Policies
This approach is different and without the use of AssumeRole or any credentials, secrets can be fetched from different AWS account. Although, secrets needs to be encrypted only through customer manager keys (It does not work for default encryption method). Follow the below steps to implement resource based secrets sharing:
- Login to Security AWS Account as admin. Create Secret in AWS Secrets Manager.
a. Select the type of secret and provide key/value pair as required
b. Select CustomerManagedKey (if already available) else choose DefaultEncryptionKey for now and change once CustomerManagedKey is created as described in Step 3.
c. Add secret name, for this instance let’s assume it’s Custom_Secret.
d. Add Resource Permission (optional) with following policy. It is used to access secrets across AWS accounts securely. Replace <account_id-987> with Consumer AWS account id or simply replace the complete arn with valid role arn to be used from consumer aws account.
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal" : {
"AWS" : "arn:aws:iam::<account_id-987>:role/Consumer_Role"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*"
} ]
}
2. If any Customer Managed Key is not available only then follow below steps:
a. Goto Key Management Service (KMS) page and navigate to Customer-managed keys tab present in left pane.
b. Click on Create Key, and keep all the default options or change settings as per convenience. Click on Next button.
c. Add Alias name (Key name) CustomerManagedKey. Add description and tags as per convenience and click on Next.
d. Add any other user or role with Key administrator if required or keep them as it is. Same can be followed while defining key usage permission and click on Next.
e. Modify Key Policy and add following code under Statements section. If other statements are also present, it is due to configuration done in prior pages. Replace <account_id-987> with Consumer AWS account id or simply replace the complete arn with valid role arn to be used from consumer aws account.
{
"Sid": "AllowUseOfTheKey",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<account_id-987>:role/Consumer_Role"
},
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "*"
}
3. Once CustomerManagedKey is created goto secrets manager and change encryption method from DefaultEncryptionKey to CustomerManagedKey.
4. Switch to Consumer AWS Account, and perform following steps:
a. Open Consumer_Role in IAM console, under permissions tab choose Add inline policy
b. Choose JSON method and paste below code. Replace resource arn of secrets manger and customer managed key (kms) with required values
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:<region_id>:<account_id-123>:secret:Custom_Secret"
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "arn:aws:kms:<region_id>:<account_id-123>:key/CustomerManagedKey"
}
]
}
c. Review and Create policy
Through Resource based policy, no temporary AWS credentials will be generated and secrets can be fetched directly using secret id.
While fetching the secret from another account complete ARN needs to be passed in SecretId, meanwhile for same account only secret name will also suffice.
Python code to validate and fetch secret from Security AWS account
import boto3
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name='us-east-1'
)
get_secret_value_response = client.get_secret_value(SecretId='arn:aws:secretsmanager:<region_id>:<account_id-123>:secret:Custom_Secret')
get_secret_value_response
If CustomerManagedKey is not select as the encryption method for the secret, then below error message will be displayed. Change the encryption method accordingly and run the process again.
References:
- https://aws.amazon.com/blogs/security/how-to-use-resource-based-policies-aws-secrets-manager-console-to-securely-access-secrets-aws-accounts/
- https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-api.html