Amazon S3 Bucket Policy not working as expected - amazon-web-services

I am trying limit a bucket access to be accessible by only one Cognito user.
I tried this policy but it's not working
{
Version: '2012-10-17',
Statement: [
{
Sid: 'AllowCognitoUserAccess',
Effect: 'Allow',
Principal: '*',
Action: ['s3:PutObject', 's3:GetObject'],
Resource: 'arn:aws:s3:::testbucketoz123/*',
Condition: {
StringEquals: {
'aws:PrincipalTag/CognitoIdentityId':
'099702b2-0c2e-42ce-8e27-3012ab6032ad',
},
},
},
{
Sid: 'AllowCognitoUserAccess',
Effect: 'Allow',
Principal: '*',
Action: ['s3:ListBucket'],
Resource: 'arn:aws:s3:::testbucketoz123',
Condition: {
StringEquals: {
'aws:PrincipalTag/CognitoIdentityId':
'099702b2-0c2e-42ce-8e27-3012ab6032ad',
},
},
},
],
};
I think there's an issue in the condition, I am trying to check if the user's Identity ID is equal to 099702b2-0c2e-42ce-8e27-3012ab6032ad
If yes then grant this user access.
What I am expecting is to allow the user that has Identity ID equal to 099702b2-0c2e-42ce-8e27-3012ab6032ad to access the S3 bucket but it not working.
Is there anything wrong with the condition?
I suspect that this condition could only be applied to IAM users and not Cognito users, anyone can confirm that?

If your CognitoIdentityId is the sub claim, use the "Access Policies" example from Understanding Amazon Cognito Authentication Part 3: Roles and Policies
{
Sid: 'AllowCognitoUserAccess',
Effect: 'Allow',
Principal: '*',
Action: ['s3:PutObject', 's3:GetObject'],
Resource: 'arn:aws:s3:::testbucketoz123/*',
Condition: {
StringEquals: {
'"cognito-identity.amazonaws.com:sub":
"us-east-1:099702b2-0c2e-42ce-8e27-3012ab6032ad"
},
},
}
Otherwise check that the Identity pool attribute mapping has your "Identity ID" mapped to CognitoIdentityId and you set up a trust policy on that authenticated role allows for "sts:TagSession" so the aws:PrincipalTag is valued.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": [
"sts:AssumeRoleWithWebIdentity",
"sts:TagSession"
],
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "{your Identity pool ID}"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}

Related

Creating MSK event source mapping for Lambda function fails

I am using the AWS-CDK to create a stack with an AWS-MSK cluster and a Lambda function which should be triggered, when a new message is available in a specific topic.
I already had it working nicely and then I decided to add clientAuthentication and now I am stuck. I am using SASL/SCRAM for authentication. I have created a custom encryption key via the KMS service and I am using that key in a Secret in the SecretsManager. I have associated that Secret with my MSK cluster and turned on clientAuthentication there.
I have also already created an interface endpoint in my VPC to the Lambda Service in order for the service to be able to access my cluster (again, this already worked when I hadn't activated clientAuthentication).
Now I am defining my Lambda listener handler function like this:
const listener = new aws_lambda.Function(this, 'ListenerHandler', {
vpc,
vpcSubnets: { subnetGroupName: 'ListenerPrivate' },
runtime: aws_lambda.Runtime.NODEJS_14_X,
code: aws_lambda.Code.fromAsset('lambda'),
handler: 'listener.handler'
});
listener.addToRolePolicy(new aws_iam.PolicyStatement({
effect: Effect.ALLOW,
actions: ['kafka:*', 'kafka-cluster:*', 'secretsmanager:DescribeSecret', 'secretsmanager:GetSecretValue'],
resources: [cluster.ref]
}));
const secretsFromLambdaAccessRole = new aws_iam.Role(this, 'AccessSecretsFromLambdaRoles', {
assumedBy: new aws_iam.ServicePrincipal('kafka.amazonaws.com')
});
secretsFromLambdaAccessRole.addToPolicy(new aws_iam.PolicyStatement({
effect: Effect.ALLOW,
actions: ['secretsmanager:DescribeSecret', 'secretsmanager:GetSecretValue'],
resources: [KAFKA_ACCESS_SECRET_ARN]
}));
listener.role?.addManagedPolicy(
aws_iam.ManagedPolicy
.fromAwsManagedPolicyName("service-role/AWSLambdaVPCAccessExecutionRole")
);
listener.role?.addManagedPolicy(
aws_iam.ManagedPolicy
.fromAwsManagedPolicyName("service-role/AWSLambdaMSKExecutionRole")
);
const kafkaAccessSecret = aws_secretsmanager.Secret
.fromSecretCompleteArn(this, 'kafkaAccessSecret', KAFKA_ACCESS_SECRET_ARN);
listener.addEventSource(new ManagedKafkaEventSource({
clusterArn: cluster.ref,
topic: "MyTopic",
startingPosition: StartingPosition.LATEST,
secret: kafkaAccessSecret,
}));
The secret also has policies assigned to it:
{
"Version" : "2012-10-17",
"Statement" : [ {
"Sid" : "AWSLambdaResourcePolicy",
"Effect" : "Allow",
"Principal" : {
"Service" : "lambda.amazonaws.com"
},
"Action" : [ "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds" ],
"Resource" : "arn:aws:secretsmanager:some-region:some-account:secret:AmazonMSK_some-secret"
}, {
"Sid" : "AWSKafkaResourcePolicy",
"Effect" : "Allow",
"Principal" : {
"Service" : "kafka.amazonaws.com"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "arn:aws:secretsmanager:some-region:some-account:secret:AmazonMSK_some-secret"
} ]
}
Now, when I try to deploy my lambda function via the CDK and it comes to the point, where it should add the event source mapping, I get this error:
Failed resources:
MskExampleStack | 17:23:22 | CREATE_FAILED | AWS::Lambda::EventSourceMapping | ListenerHandler/KafkaEventSource:MskExampleStackListenerHandler4711MyTopic (ListenerHandlerKafkaEventSourceMskExampleStackListenerHandler4711MyTopic0815)
Resource handler returned message: "Invalid request provided: Cannot access secret manager value arn:aws:secretsmanager:some-region:some-account:secret:AmazonMSK_dev-some-secret.
Please ensure the role can perform the 'secretsmanager:GetSecretValue' action on your broker in IAM. (Service: Lambda, Status Code: 400, Request ID: 123456789, Extended Request ID: null)" (RequestToken: 987654321, HandlerErrorCode: InvalidRequest)
I cannot figure out, what I am missing. What role is the error referring to? Where do I need to add the action "secretsmanager:GetSecretValue"? My user has complete Admin Rights.
You need the following:
kms permissions on the lambda role
secretsmanager permissions on the lambda role
(What I was missing) lambda.amazonaws.com in the key policy for your kms key
my setup:
lambda permissions:
- Effect: "Allow"
Action:
- kms:Decrypt
- kms:GenerateDataKey*
Resource:
- "*"
- Effect: "Allow"
Action:
- secretsmanager:GetSecretValue
Resource:
- "your secret arn"
KMS Policy:
{
"Sid": "Decrypt",
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt",
],
"Resource": "*"
}
Amazon has a knack for writing about 500 needless words to document a feature and never document things around using KMS with that feature even though it seems to vary greatly.

ECS cluster cannot use KMS key to decrypt "you are not allowed to access"

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

Error creating a skill with Cloudformation

i have a month developing alexa skills and want to create then via Cloudformation. And for that i am using this:
Lambda function
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Lambda Function from Cloud Formation by Felix Vazquez",
"Resources": {
"Lambda1": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "felix-lambda-code",
"S3Key": "hello_lambda.zip"
},
"Description": "Test with Cloud Formation",
"FunctionName": "Felix-hello-world1234",
"Handler": "lambda_function.lambda_handler",
"Role": "arn:aws:iam::776831754616:role/testRol",
"Runtime": "python2.7"
}
}
}
}
Alexa Skill
"Resources": {
"23LT3": {
"Type": "Alexa::ASK::Skill",
"Properties": {
"AuthenticationConfiguration": {
"ClientId": "+my client ID+",
"ClientSecret": "+my client Secret+",
"RefreshToken": "+The token i generate via lwa+"
},
"VendorId": "+my vendor ID+",
"SkillPackage": {
"S3Bucket": "myskillpackagebucket",
"S3Key": "my_function10.zip",
"S3BucketRole": {
"Fn::GetAtt": [
"IAMRU6TJ",
"Arn"
]
},
"Overrides": {
"Manifest": {
"apis": {
"custom": {
"endpoint": {
"uri": {
"Fn::GetAtt": [
"Lambda1",
"Arn"
]
}}}}}}}}
IAM Role
{
"Resources": {
"IAMRU6TJ": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"s3.amazonaws.com",
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "root",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}]}}]}}}}
The skill depends on the lambda and the IAM Role. When i "Create the Stack" after some seconds it gives me this error:
Could not assume the provided role. Reason: Access denied (Service: AWSSecurityTokenService; Status Code: 403; Error Code: AccessDenied; Request ID: b2e8762c-2593-11e9-b3ec-872599411915)
For the Token i use
ask util generate-lwa-tokens --scope "alexa::ask:skills:readwrite alexa::ask:models:readwrite profileā€
image of the events:
Event after execution
your Alexa::ASK::Skill Resource: 23LT3['Properties']['SkillPackage']['S3BucketRole']
The docs say
ARN of the role that grants the Alexa service permission to access the bucket and retrieve the skill package. This role is optional, and if not provided the bucket must be configured with a policy allowing this access, or be publicly accessible, in order for AWS CloudFormation to create the skill.
currently your role is allowing s3.amazonaws.com and lambda.amazonaws.com to Assume a role that can do anything in your AWS account, however you need to allow "The Alexa Service the permission..."
Best Practice would be to use least privilege necessary, but I get it if you are just testing it out.
I struggled to find the details necessary documented anywhere. Here is the role I used to get this working.
AlexaReadRole:
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- alexa-appkit.amazon.com
Sid: AllowServiceToAssumeRole
Version: 2012-10-17
Policies:
- PolicyName: "AlexaS3Read"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "s3:GetObject"
Resource: "arn:aws:s3:::<bucket-name>/<path-to-alexa-files>/*"
Type: AWS::IAM::Role

Creating CloudWatch rule with AWS CloudFormation not linking to role

I am trying to create a CloudWatch rule that triggers on a schedule and executes a state machine (Step Functions). I'm using CloudFormation to create this, and everything creates fine except for the association of the IAM role used by the rule, to the rule itself. Here is what I mean:
Notice under 'Use Existing Role' it's blank.
Here is the CF template portion that deals with the rule and its role.
"SFInvoke":{
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Sub": "states.${AWS::Region}.amazonaws.com"
}
},
"Action": "sts:AssumeRole"
}
]
},
"Policies": [
{
"PolicyName": "StepFunctionsInvoke",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"states:StartExecution"
],
"Resource": { "Ref" : "StateMachine"}
}
]
}
}
]
}
},
"CloudWatchStateMachineSDCEventRule": {
"Type":"AWS::Events::Rule",
"Properties": {
"Description":"CloudWatch trigger for the InSite Static Data Consumer",
"ScheduleExpression": "rate(5 minutes)",
"State":"ENABLED",
"Targets":[{
"Arn":{ "Ref" : "StateMachine"},
"Id":"StateMachineTargetId",
"RoleArn":{
"Fn::GetAtt": [
"SFInvoke",
"Arn"
]
}
}]
}
},
You want the SFInvoke role to show up on the Use existing role selector?
If that is the case, you need to set the Principal to events instead of states.
You're editing the event target in the screenshot above, not the step function. Principal defines the service that can assume the role, in your case that is the events service.
Try this for role creation:
"SFInvoke":{
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"Policies": [
{
"PolicyName": "StepFunctionsInvoke",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"states:StartExecution"
],
"Resource": { "Ref" : "StateMachine"}
}
]
}
}
]
}
}
Probably the Yaml would be as:
Based on the Principal: as an Events Based Services and Actions: to start the execution of a StepFunctions State Machine.
AWSEventsInvokeStepFunctions:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: AWSEventsInvokeStepFunctions
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- states:StartExecution
Resource: !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:*"
The Role which is now generic in nature can be applied to a CloudWatch Event Rule, gives Rule with the permissions to be able to start the Execution of a StepFunctions State Machine based on an Amazon S3 Event.
AmazonCloudWatchEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.s3
detail-type:
- 'AWS API Call via CloudTrail'
detail:
eventSource:
- s3.amazonaws.com
eventName:
- PutObject
requestParameters:
bucketName:
- !Ref EventBucket
Targets:
-
RoleArn: !GetAtt AWSEventsInvokeStepFunctions.Arn
Arn: !Sub "arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:MyStateMachine"
Id: !Sub "StepExecution"
You can probably check more on Start the Execution of State Machine based on Amazon S3 Event

Setting up cross account access of IAM user/role

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.