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.
Related
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
I'm trying to allow a set of users in a group access to a role through which they can upload objects to an s3 bucket.
The group as the policy:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::ACCOUNTID:role/Clinic_Sync"
}
}
The role "Clinic_Sync" has the policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SyncReqs",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::*/*"
},
{
"Sid": "SyncReqs2",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::*"
}
]
}
The bucket has the policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNTID:role/Clinic_Sync"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::mydata"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNTID:role/Clinic_Sync"
},
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::mydata/*"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::mydata",
"arn:aws:s3:::mydata/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"ADMINUSERID:*",
"ACCOUNTNO"
]
}
}
}
]
}
The idea being that no one can access the bucket except through assuming this role (other than the admin). I have created the credentials files as follows:
[default]
aws_access_key_id = ACCESSID1
aws_secret_access_key = SECRETKEY1
[csync]
role_arn = arn:aws:iam::ACCOUNTID:role/Clinic_Sync
source_profile = default
And the config file:
[default]
output = json
region = eu-west-2
[profile csync]
role_arn = arn:aws:iam::ACCOUNTID:role/Clinic_Sync
source_profile = default
The bucket policy seems to work, as running the command "aws s3 cp hello.txt s3://mydata" gives the error: Upload failed. An error occured when calling the PutObject operation: Access Denied.
But when I try to use the role, using the command "aws s3 cp hello.txt s3://run3d-data --profile csync", it gives this error:
upload failed: .\hello.txt to s3://mydata/hello.txt An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::ACCOUNTID:user/TestAcc2 is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::ACCOUNTID:role/Clinic_Sync
I've been searching the web for an answer for ages and can't find any answers. The aws documentation is frankly unintelligible to me. If anyone can help me find a solution to this I'd be much appreciated as I'm tearing my hair out here.
To reiterate, I just want the users in a particular group to have access to a role that grants them permission to use an s3 bucket, but block all other access to the bucket.
Your bucket policy seems to say: "Deny access to the bucket unless aws:userId is a given Admin User ID or Account Number. It does not reference the Role.
Therefore, accessing the bucket via the Role will be denied. This is because Deny always overrides Allow.
Writing policies with Deny can be quite difficult, as seen in this situation.
If you really want to keep a bucket secure, it is easier to put the bucket in a separate AWS Account and only grant cross-account access to the entities that should have access. This way, no Deny policy is required.
If you receive a not authorised to perform sts:AssumeRole error, make sure the Trust Policy grants access to users by selecting the Another AWS account option when creating the role. The policy should look similar to:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
I have a bucket with empty bucket policy, block public access turned ON (ACLs and Bucket) and trying to list buckets using IAM policy tied to user using STS AssumeRole with following attached policy.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject",
"s3:GetBucket*",
"s3:ListBucket*",
"s3:ListAllMyBuckets"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::my-test-bucket/*"
]
}
]
}
The assumed role credentials are used during the STS session in python (boto3)
s3c = boto3.client('s3',
aws_access_key_id=credentials['AccessKeyId'],
aws_secret_access_key=credentials['SecretAccessKey'],
aws_session_token=credentials['SessionToken'])
s3c.list_buckets()
I get this exception:
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
When I tried to use IAM Policy simulator, it indicates "Implicitly denied". Im thinking if I need to access a bucket policy for this user? My understanding has been if both IAM and Bucket policy, it is an intersection. If either is not present, the other takes precedence.
Calling list_buckets() uses the s3:ListAllMyBuckets permission.
This permission cannot be restricted to a specific bucket. A user can either list all of the buckets in the account, or none of them.
Calling operations on a bucket (ListBucket, GetBucket*) requires permission for the bucket itself.
Operations on objects requires permission for the objects (or /* after the bucket name to permit actions on all objects).
Therefore, you can change your policy to:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucket*"
],
"Resource": "arn:aws:s3:::my-test-bucket"
},
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-test-bucket/*"
}
]
}
This is a pretty common issue because people tend to miss the difference between a "bucket" resource and an "object" resource. A bucket ends in the name of the bucket (arn:aws:s3:::my-test-bucket) whereas an object includes the bucket and key, and is often granted with a star after the initial slash. So, just change your policy to the following.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:ListAllMyBuckets"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::my-test-bucket"
]
},
{
"Action": [
"s3:GetObject",
"s3:GetBucket*",
"s3:ListBucket*"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::my-test-bucket/*"
]
}
]
}
I have two AWS accounts (account A, and account B). Account A has an EC2 instance, and that instance wants to do a put item to a dynamodb located in account B.
Since it is cross-account access, I created an IAM role on account B to allow account A to do put_item, an IAM role on account A to assume that role and attached the IAM role on the EC2 instance
When I run my program, I get an error message saying that I am trying to use the assume role to put an item to a table that in the same account. (in my code i just sepcified the Account B table name)
It seems that the instance doesn’t realize that the table is on account B even I have the assumerole setup. What am I missing here?
I have also verified that I can put item using AWS CLI (after performing the STS call).
Is there any Java API that I can to specify which dynamodb arn that I want to put the item to?
Error message:
User: arn:aws:sts::ACCOUNT_A:assumed-role/Assume-role/INSTANCE_ID is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-east-1:ACCOUNT_A:table/TABLE_NAME (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: AccessDeniedException)
Policy on account A:
{
"Version": "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Action": [ "sts:AssumeRole", "sts:GetFederationToken" ],
"Resource": "arn:aws:iam::AccountA:role/PutItem" },
{ "Effect": "Allow",
"Action": [ "sts:DecodeAuthorizationMessage", "sts:GetAccessKeyInfo", "sts:GetCallerIdentity" ],
"Resource": "*" } ]
}
Policy on Account B:
{
"Version": "2012-10-17",
"Statement": [ {
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [ "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:UpdateTable" ],
"Resource": "arn:aws:dynamodb:region:accB:table/table name" },
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": "*" } ]
}
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": {}
}