aws secrets manger and multiple accounts - amazon-web-services

I have a secret in one account that I want to share in another account. In the other account we have a lambda function that will need this secret. I followed this and it works great.
AWS share secrets between accounts
Now we want to see if instead of granting access to every user that invokes this lambda is there a way to grant access to a group or a role in the other account access to the secret. I tried using the role that invokes the function but I got denied in the response for the lambda. Then next I tried a group in the other account but it wouldn't let me save it. I just kept telling the principal was not correct. Thanks.
So here is what I used for policies.
Policy on the Customer Managed Key
{
"Sid": "Permissions for external users",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::external-acct:role/Cross-Account-KMS-Role"
},
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:us-east-1:central-acct:secret:my-secret"
}
}
}
Now on the secret itself we set this policy up.
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal" : {
"AWS" : "arn:aws:iam::external-acct:role/Cross-Account-KMS-Role"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*",
"Condition" : {
"ForAnyValue:StringEquals" : {
"secretsmanager:VersionStage" : "AWSCURRENT"
}
}}
Then on the external account we created this policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:central-acct:secret:my-secret"
},
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:us-east-1:central-acct:key/customer-key-1"
}
]
}
then we atached the policy to the Role above. Now when i did this for my own account instead of the role I can use aws cli and pull the secret. Now of course i wasn't using the role but my account.

Ok, So I figured it out. It seems that the resource policy on the CMK was wrong. I had used one like this
arn:aws:kms:us-east-1:my_acct:key/my_policy
When I needed one like this.
arn:aws:kms:us-east-1:my_acct:key/my_policy_id

Related

AWS IAM. How allow all resources with some tag?

I need to write policy to allow see all Secrets with some tag. But when I use condition, user with this policy loses all access. What am I doing wrong?
Here is my policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:ListSecrets"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/ProjectName": "Test"
}
}
}
]
}
Here is my Secret
But in result I have this message: You don't have permission to view or select from existing secrets in your account. Contact your administrator to obtain ListSecrets access.

Sharing AWS Secrets Manager with another account is not working

I need to share an AWS Secrets Manager secret with multiple accounts.
For this public post, I've scrubbed the account numbers and replaced them with dummy values.
For this example, the account holding the secret is 987654 and it needs to be accessed by account 123456
The account that will "read" the secret (123456) should be able to read from "ANY ROLE" within the account.
Note: I tried using a wildcard in the principal (ex: "arn:aws:iam::123456:role/*") but I got a malformed policy error. So I'm using conditionals.
The secret is using a KMS key with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::987654:role/Admin1",
"arn:aws:iam::987654:role/Terraform"
]
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:CallerAccount": [
"987654",
"123456"
]
}
}
}
]
}
The secret policy:
{
"Version" : "2012-10-17",
"Statement" : [ {
"Sid" : "",
"Effect" : "Allow",
"Principal" : {
"AWS" : "*"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*",
"Condition" : {
"StringEquals" : {
"aws:SourceAccount" : [ "987654", "123456" ]
}
}
} ]
}
When reading the key from account 987654 it works fine. When I try to read the secret from role in account 123456 I get AccessDeniedException:
An error occurred (AccessDeniedException) when calling the GetSecretValue operation: User: arn:aws:sts::123456:assumed-role/Admin/sessionfoo is not authorized to perform: secretsmanager:GetSecretValue on resource: arn:aws:secretsmanager:us-east-1:987654:secret:test because no resource-based policy allows the secretsmanager:GetSecretValue action
I am testing with:
aws secretsmanager get-secret-value --secret-id 'arn:aws:secretsmanager:us-east-1:987654:secret:test'
What's wrong with my policies? Thanks!

AWS secret manager access deny issue

I have a secret key (USRFTP) stored in ACCOUNT A, I want to access this key from EC2 box with role ASHISHROLE in ACCOUNT B. I am running python code to get secret key as given below, Using resource policy in secret key as given below, KMS policy is as given below, But still getting this issue
botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the GetSecretValue operation: User: arn:aws:sts::ACCOUNTB:assumed-role/ASHISHROLE /i-*********is not authorized to perform: secretsmanager:GetSecretValue on resource: arn:aws:secretsmanager:us-east-2:ACCOUNTA:secret:USRFTP-KJHJH
import boto3
import base64
from botocore.exceptions import ClientError
def get_secret():
secret_name = "arn:aws:secretsmanager:us-east-2:ACCOUNTA:secret:USRFTP"
region_name = "us-east-2"
# Create a Secrets Manager client
session = boto3.session.Session()
client = session.client(
service_name='secretsmanager',
region_name=region_name
)
print("here")
get_secret_value_response = client.get_secret_value(
SecretId=secret_name
)
if 'SecretString' in get_secret_value_response:
return get_secret_value_response['SecretString']
else:
return base64.b64decode(get_secret_value_response['SecretBinary'])
print(get_secret())
SECRET KEY RESOURCE POLICY
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal" : {
"AWS" : "arn:aws:iam::ACCOUNTB:role/ASHISHROLE"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*"
} ]
}
KMS POLICY
{
"Id": "key-consolepolicy-3",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNTA:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNTA:role/OKin"
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNTB:root"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNTB:root"
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
The most difficult concept with cross-account permissions is that it requires granting permission from both directions.
In your situation, you have:
Secrets Manager in Account-A
EC2 instance in Account-B
An IAM Role (Role-B) in Account-B
This requires permissions from A to B:
The Secret in Account-A needs a "Secret Key Resource Policy" that permits access from Role-B (You have already done this)
And it also requires permissions from B to A:
Role-B must be given permission to access the Secret in Account-A
This might seem strange, but I like to think of it like this:
By default, an IAM User / IAM Role has no permission
To use the Secrets Manager (even in the same account), the IAM Role must be given permission such as secretsmanager:GetSecretValue -- otherwise it isn't permitted to do anything
By default, an AWS Account cannot be accessed from another AWS Account (eg I cannot access your account)
If an AWS Account is willing to have another account access it, then it must grant access. This can be done at the resource-level in services such as S3, SNS, SQS, KMS and Secrets Manager because they have the ability to create policies on resources. Services without this capability cannot grant cross-account access and must be used by assuming a role in the same account.
The configuration in your question appears to be missing the permissions that need to be granted to Role-B to access the Secrets Manager, such as:
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-2:ACCOUNTA:secret:USRFTP"
}
]
}
Thank you John for your answer, but I wanted to piggyback off of you because I also had this same issue. One thing I also noticed is that the "Principal" key is required when setting up these permissions. So here is something similar to what I had to do, just replaced my Principal value with a wildcard:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "ALLOW",
"Action": "secretsmanager:GetSecretValue",
"Principal": "*",
"Resource": "**Your:resource:name:here**"
}
]
}
So just make sure the Principal key is included at minimum and you should be good.

Assigning permission to single cognito user access to a secret created on AWS's Secret Manager

I have created a secret on AWS's Secrets Manager. I have a python service with cognito authentication, and I want to assign to a particular user permission to get this secret. I created the following policy to allow users to get the secret's value.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:*:*:secret:test_secret*"
}
]
}
I've then assigned this policy to my cognito identity pool's Authenticated role. Now every user in this pool has permission to get this secret's value. But I need to assign this permission to a single user, not all of them. Is there any way to do this?
You can put this user in a group and let this group assume a IAM Role.
Then attach the right to the IAM Role.
Role-Based Access Control
You can write your authenticated user IAM policy in a way that it only allows them permission to access resources that they create. E.g.:
Instantiate an AWS secretsmanager client using the ID token you get from CognitoIdentity
Specify your authenticated policy to look something like this:
{
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"secretsmanager:UpdateSecret",
"secretsmanager:PutSecretValue",
"secretsmanager:DescribeSecret",
"secretsmanager:DeleteSecret"
],
"Resource": "*",
"Condition": {
"ForAllValues:StringEquals": {
"aws:TagKeys": [
"Sub",
"Service"
]
},
"StringEquals": {
"secretsmanager:ResourceTag/Service": "MYSERVICE",
"secretsmanager:ResourceTag/Sub": "${cognito-identity.amazonaws.com:sub}"
}
}
},
{
"Sid": "",
"Effect": "Allow",
"Action": [
"secretsmanager:TagResource",
"secretsmanager:CreateSecret"
],
"Resource": "*",
"Condition": {
"ForAllValues:StringEquals": {
"aws:TagKeys": [
"Sub",
"Service"
]
},
"StringEquals": {
"aws:RequestTag/Service": "MYSERVICE",
"aws:RequestTag/Sub": "${cognito-identity.amazonaws.com:sub}"
}
}
}
]
}
}
3) When you create the secret, be sure to apply tags in the CreateSecret request that map to your users identitypoolid and service name. (If you don't, your request will fail.)
Your users will now only be able to access secrets that they create. This is secure because the "${cognito-identity.amazonaws.com:sub}" value will be interpolated based on the AWS SDK session credentials. I.e. your other users' clients will have different "sub" values embedded as part of their session credentials, so they won't be able to access secrets they didn't create.

AWS assume role access denied while using SDK

I am using go sdk to create a new role and assume it. Both are done with same IAM user.
The role trust relationship is as follows:
{
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "<an admin user>" },
"Action": [ "sts:AssumeRole" ]
}]
}
Later when trying to add object to a bucket, I can create a session token,
but the PutObject operations fails with AccessDenied.
The bucket policy is:
{
"Effect": "Allow",
"Action":"s3:*",
"Resource": [
"arn:aws:s3:::<name of the bucket>/*"
],
"Condition": {}
}
If the role you are assuming does not grant access to the S3 bucket via the role policies, you'll need to add the role as a principal to the bucket policy.
There's a handy tool here; https://awspolicygen.s3.amazonaws.com/policygen.html that helps with generating bucket policies. But it should end up looking like:
{
"Effect": "Allow",
"Action":"s3:*",
"Principal": {
"AWS": ["arn:aws:iam::<accountid>:role/<name of assumed role>"]
},
"Resource": [
"arn:aws:s3:::<name of the bucket>/*"
],
"Condition": {}
}