I have a main account user that I want to allow access to a subaccount S3 bucket. I have setup the following stack in my subaccount
AWSTemplateFormatVersion : '2010-09-09'
Description: 'Skynet stack to allow admin account deploying user to access S3'
Parameters:
AccountId:
Type: String
Description: Account ID of admin account (containing user to allow)
Username:
Type: String
Description: Username to be allowed access
BucketPrefix:
Type: String
Description: Bucket to be allowed (prefix appended with -{AccountId}-{Region})
Resources:
CrossAccountRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
AWS:
- !Sub arn:aws:iam::${AccountId}:user/${Username}
Path: /
Policies:
- PolicyName: skynet-s3-delegate
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:GetObject
Resource: "*"
But I find that I still get an error when I try to assume the role:
aws s3 cp skynet-lambda.zip s3://skynet-lambda-TARGET_ACCOUNT_ID-ap-southeast-1 --profile skynetci-cross-account
An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::MAIN_ACCOUNT_ID:user/circleci-skynet is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::TARGET_ACCOUNT_ID:role/StackSet-df0e85b0-d6fd-47bf-a0bb-CrossAccountRole-1EW45TXEFAY0D
Why is this so considering I already have the following policy for the user
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Resource": "arn:aws:iam::TARGET_ACCOUNT_ID:role/StackSet-df0e85b0-d6fd-47bf-a0bb-CrossAccountRole-1EW45TXEFAY0D"
}
You need to have Bucket Policy update to allow cross account access a sample policy would be like:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::AccountB-ID:root"
},
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::examplebucket"
]
}
]
}
Also make sure IAM user who is trying to access has this inline policy attached:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::examplebucket"
]
}
]
}
You can refer AWS Documentation
I am attaching a working example that I tested using two of my accounts.
STEP 1: CloudFormation YAML template:
AWSTemplateFormatVersion : '2010-09-09'
Description: 'Skynet stack to allow admin account deploying user to access S3'
Parameters:
AccountId:
Type: String
Description: Account ID of admin account (containing user to allow)
Username:
Type: String
Description: Username to be allowed access
BucketPrefix:
Type: String
Description: Bucket to be allowed (prefix appended with -{AccountId}-{Region})
Resources:
CrossAccountRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
AWS:
- !Sub arn:aws:iam::${AccountId}:user/${Username}
Path: /
Policies:
- PolicyName: skynet-s3-delegate
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:ListBucket
- s3:GetObject
Resource: "*"
RootInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
-
Ref: "CrossAccountRole"
STEP 2: Create the cross account profile
Modify ~/.aws/credentials. Add a new profile called "skynetci-cross-account". Modify based upon your parameters created in STEP 1. You will need the role arn to replace the one below. You will also need the profile name for the account that you are giving permission to. In this example the profile name is "default".
Example here:
[skynetci-cross-account]
role_arn = arn:aws:iam::191070ABCDEF:role/Test-CrossAccountRole-IZDDLRUMABCD
source_profile = default
STEP 3: Test cross access
aws --profile skynetci-cross-account s3 ls s3://bucket-name
To accomplish your goal, you need to set a bucket policy in your target S3 bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DelegateS3Access",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::MAIN_ACCOUNT_ID:USER_NAME"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::BUCKET_NAME/*",
"arn:aws:s3:::BUCKET_NAME"
]
}
]
}
And allow S3 permissions to this user.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"*"
]
}
]
}
In this case you do not need assume a role on the target account. The user itself will be able to access to bucket in another account.
Related
I have an S3 bucket on which I am trying to apply the bucket policy via CloudFormation. I want to allow two IAM roles to access the bucket and is achieved by specifying the ARN of the roles in the bucket policy in the CloudFormation template.
Below is the CloudFormation template:
LandingBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref LandingBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
# yamllint disable-line rule:line-length
- Sid: "Allow s3 permission"
Action:
- s3:PutObject
- s3:GetObject
- s3:ListBucket
Effect: "Allow"
Resource:
- !GetAtt LandingBucket.Arn
- !Sub "${LandingBucket.Arn}/*"
Principal:
AWS:
- !Ref IamRoleArn1
- !Ref IamRoleArn2
Parameters are: IamRoleArn1: arn:aws:iam::1234:role/xyz, IamRoleArn2: arn:aws:iam::1234:role/abc
The final policy from the console looks like below
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "file drop permission",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::1234:role/xyz",
"AROxxIECxx"
]
},
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::bucket-name",
"arn:aws:s3:::bucket-name/*"
]
}
]
}
The first Principal is an IAM role, however, the second one looks like an API key even though in the CloudFormation template I have mentioned the second IAM role ARN just like the first IAM role.
Why is the second role ARN not showing up in the bucket policy?
That is the unique identifier of that particular resource. In this case it is called a RoleId and ARN is just a readable format of the same. Both representation points to the same resource in AWS.
Try running
aws iam get-role --role-name "<you role here>"
the output of this command will have a field named RoleId and should that should clear things out for you.
The unique identifier that starts with AROA represents that it is a role related resource.
I have recently started to use Control Tower from AWS to manage my multiple account environment.
My current question is:
I have a bucket belonging to the master account that I would like to share console access with some of the accounts of the organization. How can I do that? I have tried adding a bucket policy specifying the accounts and an SSO permission set attached to that account granting access to the bucket but when accessing with that role to s3 I can't see that bucket.
I am able to access the bucket through CLI but not through console, though. I.e. When accessing with the assigned role through CLI I am able to do aws s3 ls s3://mybucket and it shows the folders inside it (other commands work as well). But when doing aws s3 ls the bucket is not listed.
bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example permissions",
"Effect": "Allow",
"Principal": {
"AWS": [
"123456789101",
"112131415161",
]
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::mybucket"
}
]
}
permission set:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Example",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::mybucket",
"arn:aws:s3:::mybucket/*"
]
}
]
}
Does anyone know how to allow the users to list it with the rest of the account buckets and through the console on the s3 page?
Thank you!!
Daiana
As I understand ControlTower, you are not supposed to do anything meaningful in the root account.
Also, there is no shared Console access unless you allow other users to "federate" into the very same account where the bucket was created. Using the ControlTower this is usually done via Single-Sign-On (SSO)
My suggestion is: Create a Shared Services/Resources account and allow access to those resources to any member of your organization. Do this by making use of the new AWS:PrincipalOrgID. For example, see this CloudFormation Snippet for a central SNS queue with sns:Publish permission from within the AWS organization.:
Resources:
Topic:
Type: AWS::SNS::Topic
Properties:
DisplayName: Name
TopicName: name
TopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref Topic
PolicyDocument:
Version: '2012-10-17'
Statement:
# default permission allow same account: https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html
- Sid: __default_statement_ID
Effect: Allow
Principal:
AWS: "*"
Action:
- SNS:GetTopicAttributes
- SNS:SetTopicAttributes
- SNS:AddPermission
- SNS:RemovePermission
- SNS:DeleteTopic
- SNS:Subscribe
- SNS:ListSubscriptionsByTopic
- SNS:Publish
- SNS:Receive
Resource: !Ref Topic
Condition:
StringEquals:
AWS:SourceOwner: !Sub ${AWS::AccountId}
- Sid: SnsTopicPolicy
Effect: Allow
Principal:
AWS: "*"
Condition:
StringEquals:
# allow access from within your organization
AWS:PrincipalOrgID: "o-xxxxxxxxxx"
Action: sns:Publish
Resource: !Ref Topic
I am trying to create an AWS API Gateway of PRIVATE type,
This requires a resource policy, which I have as I'm able to create the gateway from the AWS Console,
I wanted to know how I could add the resource policy via the CF template -
Following is the swagger definition of the resource policy -
x-amazon-apigateway-policy:
Version: "2012-10-17"
Statement:
- Effect: "Deny"
Principal: "*"
Action: "execute-api:Invoke"
Resource: "arn:aws:execute-api:us-east-1:awsAccountId:xxxx/*/*/*"
Condition:
StringNotEquals:
aws:sourceVpc: "vpc-xxxxx"
- Effect: "Allow"
Principal: "*"
Action: "execute-api:Invoke"
Resource: "arn:aws:execute-api:us-east-1:xxxx:xxxx/*/*/*"
How can I configure it in the CF template -
AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Description: G2G Api Template Stack
Resources:
g2gPrivate:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: 'private-gw'
EndpointConfiguration:
Types:
- PRIVATE
Reference -
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html
https://medium.com/#cathmgarcia/conditional-resource-policy-on-aws-sam-with-inline-swagger-816ce946dbb
You need to supply the policy under a key (called Policy at the same level as Name.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-policy
This needs to be supplied in the JSON format.
Something like...
AWSTemplateFormatVersion: 2010-09-09
Transform: 'AWS::Serverless-2016-10-31'
Description: G2G Api Template Stack
Resources:
g2gPrivate:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: 'private-gw'
EndpointConfiguration:
Types:
- PRIVATE
Policy: !Sub |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:${AWS::AccountId}:*/*/*/*",
"Condition": {
"StringNotEquals": {
"aws:sourceVpc": "vpc-xxxxx"
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:${AWS::AccountId}:*/*/*/*"
}
]
}
I continue to get the error:
software.amazon.awssdk.services.kms.model.KmsException: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.
When attempting to decrypt.
I've created a Task execution role with the permission:
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
],
"Policies": [
{
"PolicyName": "AllowKmsDecrypt",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
{"Ref": "PrincipalSourceKeyArn"}
]
}
]
}
}
]
And the task definition is associated with the role:
"ExecutionRoleArn": {"Ref": "TaskExecutionRoleArn"},
Hm. What else could i be missing?
From these docs it turns out an IAM policy is not sufficient:
IAM policies by themselves are not sufficient to allow access to a
CMK. However, you can use them in combination with a CMK's key policy
if the key policy enables it. Giving the AWS account full access to
the CMK does this; it enables you to use IAM policies to give IAM
users and roles in the account access to the CMK
I needed to update the KMS KeyPolicy to include:
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": { "Fn::Join" : ["" , ["arn:aws:iam::", {"Ref" : "AWS::AccountId"} ,":root" ]] }
},
"Action": "kms:*",
"Resource": "*"
}
In case of this line
{ "Fn::Join" : ["" , ["arn:aws:iam::", {"Ref" : "AWS::AccountId"} ,":root" ]] }
you are allowing to use this key by root account only.
Usually, this key policy has to provide manage possibilities for users and only a few specific actions for services or other users that use this key. So as for me the whole set up has to look something like this:
KMSKeyEncryption:
Type: AWS::KMS::Key
Properties:
Enabled: true
EnableKeyRotation: false
KeyPolicy:
Version: 2012-10-17
Statement:
- Principal:
AWS:arn of the users/roles who are allowed to manage this key
Effect: Allow
Action:
- kms:Create*
- kms:Describe*
- kms:Enable*
- kms:List*
- kms:Put*
- kms:Update*
- kms:Revoke*
- kms:Disable*
- kms:Get*
- kms:Delete*
- kms:ScheduleKeyDeletion
- kms:CancelKeyDeletion
- kms:Encrypt*
- kms:Decrypt*
Resource: "*"
- Principal: "*" # this is not specific enough, should be strict
Effect: Allow
Action:
- kms:Decrypt*
Resource: "*"
PolicyDecryptKms:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: DecryptKmsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowDecryptValues
Effect: Allow
Action:
- kms:Decrypt*
Resource: !GetAtt KMSKeyEncryption.Arn
RoleECSTaskContainer:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2008-10-17
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
RoleName: ECSTaskContainerRole
ManagedPolicyArns:
- !Ref PolicyDecryptKms
I created an SQS queue and added policy under permission tab allowing only my account users to configure the configure the notification
Policy Document
{
"Version": "2012-10-17",
"Id": "arn:aws:sqs:us-east-1:111111111111:sqsqueue/SQSDefaultPolicy",
"Statement": [
{
"Sid": "Sid111111111111",
"Effect": "Allow",
"Principal": {
"AWS": "111111111111"
},
"Action": [
"sqs:SendMessage",
"sqs:ReceiveMessage"
],
"Resource": "arn:aws:sqs:us-east-1:111111111111:queue"
}
]
Navigate to S3 and try to configure event notification for the above queue, it is throwing an error
Unable to validate the following destination configurations. Permissions on the destination queue do not allow S3 to publish
notifications from this bucket.
(arn:aws:sqs:us-east-1:111111111111:queue)*
am I doing something wrong? Can someone help me please
I was able to resolve this issue by adding "Service": "s3.amazonaws.com"
in the Principal tag.
Here the policy document
{
"Version": "2012-10-17",
"Id": "arn:aws:sqs:us-east-1:111111111111:sqsqueue/SQSDefaultPolicy",
"Statement": [
{
"Sid": "Sid111111111111",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": [
"sqs:SendMessage",
"sqs:ReceiveMessage"
],
"Resource": "arn:aws:sqs:us-east-1:111111111111:queue"
}
]
This is explained in https://forums.aws.amazon.com/thread.jspa?threadID=173251
This template file creates a bucket, SQS Queue and a policy to connect the two:
AWSTemplateFormatVersion: 2010-09-09
Parameters:
IncomingBucketName:
Type: 'String'
Description: 'Incoming Bucket Name'
Default: 'some-bucket-name-here'
Resources:
IncomingFileQueue:
Type: 'AWS::SQS::Queue'
Properties: {}
SQSQueuePolicy:
Type: 'AWS::SQS::QueuePolicy'
Properties:
PolicyDocument:
Id: 'MyQueuePolicy'
Version: '2012-10-17'
Statement:
- Sid: 'Statement-id'
Effect: 'Allow'
Principal:
AWS: "*"
Action: 'sqs:SendMessage'
Resource:
Fn::GetAtt: [ IncomingFileQueue, Arn ]
Queues:
- Ref: IncomingFileQueue
IncomingFileBucket:
Type: 'AWS::S3::Bucket'
DependsOn:
- SQSQueuePolicy
- IncomingFileQueue
Properties:
AccessControl: BucketOwnerFullControl
BucketName:
Ref: IncomingBucketName
NotificationConfiguration:
QueueConfigurations:
- Event:
s3:ObjectCreated:Put
Queue:
Fn::GetAtt: [ IncomingFileQueue, Arn ]
I was getting the same issue but used this page to work out how to connect the three resources in order to successfully deploy the stack:
https://aws.amazon.com/premiumsupport/knowledge-center/unable-validate-destination-s3/
I'm still working on the Policy Condition as the form recommended in the above link doesn't work for SQS. That being the case, the above template is not secure and shouldn't be used in production as it allows anyone to add messages to the queue.
I'll update this answer once I've figured that bit out...