I am using a docker image of Minio in a Node development environment. The database seed creates a Minio bucket thusly:
await this.s3.createBucket({
Bucket: this.configService.get('S3_BUCKET_NAME'),
ACL: 'public'
}).promise()
This creates the bucket nicely, but the ACL doesn't take at all. I can jump into the Minio browser at http://localhost:9000 and manually set the bucket to public read, but that's obviously kind of cumbersome for a seed.
I've seen a lot of conflicting advice, suggesting things like "Minio doesn't even do ACLs, use a bucket policy," but I can't find a sample policy file anywhere, and the AWS JSON don't seem to work. I would really prefer not to do this via the CLI interface, as I don't want to have to build that into my deployments. Am I missing something?
An example can be found here:
Set Bucket Policy in minio-js (node-js)
var Minio = require('minio')
var s3Client = new Minio.Client({
endPoint: '<host>',
accessKey: 'YOUR-ACCESSKEYID',
secretKey: 'YOUR-SECRETACCESSKEY'
})
// Bucket policy - GET requests on "testbucket" bucket will not need authentication.
var policy = `
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::testbucket"
],
"Sid": ""
},
{
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
"arn:aws:s3:::testbucket/*"
],
"Sid": ""
}
]
}
`
s3Client.setBucketPolicy('testbucket', policy, (err) => {
if (err) throw err
console.log('Set bucket policy')
})
The issue turned out to be that one cannot create the bucket and assign the policy in the same call. There needs to be two calls.
This wound up working:
const S3_BUCKET = 'some_bucket_name'
const policy = JSON.stringify({
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Principal": {
"AWS": [
"*"
]
},
"Resource": [
`arn:aws:s3:::${S3_BUCKET}/*`
],
"Sid": ""
}
]
})
try {
await this.s3.createBucket({ Bucket: S3_BUCKET }).promise()
await this.s3.putBucketPolicy({ Bucket: S3_BUCKET, Policy: policy }).promise()
} catch(error) {
this.logger.error(error, 'create:bucket')
}
Related
I'm trying to use an AWS lambda function (deployed with SAM) to rotate a secret. Reading AWSSecretsManagerRotationPolicy description says:
Gives permission to rotate a secret in AWS Secrets Manager. Source
Based on that, this is applied to a single secret, but seeing the Policy definition seems like it permits all secrets for a given Partition, Region, and AccountId:
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:DescribeSecret",
"secretsmanager:GetSecretValue",
"secretsmanager:PutSecretValue",
"secretsmanager:UpdateSecretVersionStage"
],
"Resource": {
"Fn::Sub": "arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*"
},
"Condition": {
"StringEquals": {
"secretsmanager:resource/AllowRotationLambdaArn": {
"Fn::Sub": [
"arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${functionName}",
{
"functionName": {
"Ref": "FunctionName"
}
}
]
}
}
}
},
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetRandomPassword"
],
"Resource": "*"
}
]
Is the description misleading, or did I misinterpret something?
I am trying to avoid having to implement fine-grained ElasticSearch policy until we absolutely need it since it is irreversible. So, I am implementing a Domain JSON defined access policy with the conditions noting the IpAddress allowed or denied. This is for requests through a browser to the Kibana dashboard, so this needs to work through unsigned requests.
Looking at Identity and Access Management in Amazon OpenSearch Service, I understand that I should be able to limit by domain, index, and documents by desired actions (i.e. GET, POST, PUT, etc) for whichever IpAddress. However, unless I have it wide open by domain, I keep getting the error message:
"User: anonymous is not authorized to perform: es:ESHttpGet because no
resource-based policy allows the es:ESHttpGet action"
My Access Policy doesn't look like it has any syntax error in it to me. I am wondering if there is a setting I need to set to allow this that I am missing. I haven't found any reference to any such thing so far, unless I overlooked it.
My Access Policy looks something like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:region:id:domain/domainname/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"123.123.123.123",
"456.456.456.456"
]
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:ESHttpGet",
"Resource": "arn:region:id:domain/domainname/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"789.789.789.789"
]
}
}
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:ESHttpGet",
"Resource": "arn:region:id:domain/domainname/indexname1/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"120.450.780.230"
]
}
}
},
{
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "es:ESHttpGet",
"Resource": "arn:region:id:domain/domainname/indexname2/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"120.450.780.230"
]
}
}
}
]
}
It is anything but the first Effect clause, which is wide open, that gives me the error message. I don't know what I am missing. It looks virtually identical to the documentation.
I am also trying to prevent the deletion of the indexes and data through this access policy and haven't found that syntax.
Thanks for your help in advance.
In my use case, I want to access DynamoDB table created in AWS account A and Lambda created in account B. For this I have followed many references on Internet which suggests me to use AWS assume role feature.
I have added following permission in Lambda execution role
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::aws-account-A-number:role/test-db-access"
}
}
Following is the trust relationship of Lambda
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::aws-account-A-number:root"
},
"Action": "sts:AssumeRole"
}
]
}
In account A, I have created role(test-db-access) for allowing others to access this account and added AmazonDynamoDBFullAccess and AdministratorAccess policies. Following is the trust relationship I have added in this account
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::aws-account-B-number:role/sam-dev-test-
TestLambda-LambdaRole-1FH5IC18J0MYT"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Following is the Java code I have added to access Dynamo DB instance
AssumeRoleRequest assumeRequest = new AssumeRoleRequest()
.withRoleArn("arn:aws:iam::aws-account-A-number:role/test-db-access").withRoleSessionName("cross_acct_lambda").withDurationSeconds(900);
final AWSSecurityTokenService sts = AWSSecurityTokenServiceClientBuilder.standard().withRegion("eu-west-1").build();
final Credentials credentials = sts.assumeRole(assumeRequest).getCredentials();
following is the crash log coming on executing lambda
{
"errorMessage": "User: arn:aws:sts::aws-account-B-number:assumed-role/sam-dev-test-TestLambda-LambdaRole-1FH5IC18J0MYT/sam-dev-test-TestLambda-LambdaFunction-73TVOBN6VXXX is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::aws-account-A-number:role/test-db-access (Service: AWSSecurityTokenService; Status Code: 403; Error Code: AccessDenied; Request ID: 100bd3a3-3f9c-11ea-b642-d3b4d9ff35de)",
"errorType": "com.amazonaws.services.securitytoken.model.AWSSecurityTokenServiceException"
}
It appears your requirements are:
From an AWS Lambda function in Account-B, access a DynamoDB table in Account-A
To reproduce your situation I did the following:
Created a DynamoDB table in Account-A
Created an IAM Role (Role-A) in Account-A with the following policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:ap-southeast-2:<Account-A>:table/Inventory"
}
]
}
And this Trust Relationship (pointing to the Role created in the next step):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<Account-B>:role/role-b"
},
"Action": "sts:AssumeRole"
}
]
}
Created an IAM Role (Role-B) in Account-B for use with the Lambda function, with this policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<Account-A>:role/role-a"
}
]
}
And with this Trust Relationship:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Created an AWS Lambda function in Account-B that will:
Assume Role-A in Account-A
Access the DynamoDB table in Account-A
I'm a Python person, so my function is:
import boto3
def lambda_handler(event, context):
# Assume Role
sts_client = boto3.client('sts')
response = sts_client.assume_role(
RoleArn='arn:aws:iam::<Account-A>:role/stack-role-a',
RoleSessionName='bar')
session = boto3.Session(
aws_access_key_id=response['Credentials']['AccessKeyId'],
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
aws_session_token=response['Credentials']['SessionToken']
)
# Update DynamoDB
dynamodb_client = session.client('dynamodb')
dynamodb_client.update_item(
TableName='Inventory',
Key={'Item': {'S': 'foo'}},
UpdateExpression="ADD #count :increment",
ExpressionAttributeNames = {
'#count': 'count'
},
ExpressionAttributeValues = {
':increment': {'N': '1'},
}
)
I tested this by clicking Test on the Lambda function in Account-B. It successfully updated the DynamoDB table in Account-A.
I suspect the difference is with your trust policies, which appear to be a little bit different.
I am trying to give lambda execution access to select members within a group. Users are authenticated via PingFederate. I am having issue granting this selective access to federated user.
I have a custom IAM policy (allow-lambda-invocation-selective) attached to this role. Although the policy seems to pass validation and policy simulation shows access is allowed, when I try to execute the lambda function I get message
Calling the invoke API action failed with this message: User:arn:aws:sts::123456789012:assumed-role/role-for-grp-l2/myuser1234 is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-east-1:123456789012:function:my-lambda-function
Here is my policy: allow-lambda-invocation-selective
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction",
"lambda:InvokeAsync",
"lambda:ListVersionsByFunction",
"lambda:GetFunction",
"lambda:ListAliases"
],
"Resource": "arn:aws:lambda:*:123456789012:function:my-lambda-function",
"Condition": {
"StringEquals": {
"aws:userid": "arn:aws:sts::123456789012:assumed-role/role-for-grp-l2/myuser1234"
}
}
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"lambda:ListFunctions",
"lambda:ListEventSourceMappings",
"lambda:ListLayers",
"lambda:ListLayerVersions"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:userid": "arn:aws:sts::123456789012:assumed-role/role-for-grp-l2/myuser1234"
}
}
}
]
}
Am i missing something?
I'm trying to understand your problem. Correct me if I made a wrong supposition.
Every group/user already have its own role.
When you authenticate your users, they have their assumed role. myuser1234, when authenticated, will receive arn:aws:sts::123456789012:assumed-role/role-for-grp-l2/myuser1234 role, right? Is it possible to create one role for each group and remove the conditions property (check item 2 explaining why)?
// role-for-grp-l2
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction",
"lambda:InvokeAsync",
"lambda:ListVersionsByFunction",
"lambda:GetFunction",
"lambda:ListAliases"
],
"Resource": "arn:aws:lambda:*:123456789012:function:my-lambda-function"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"lambda:ListFunctions",
"lambda:ListEventSourceMappings",
"lambda:ListLayers",
"lambda:ListLayerVersions"
],
"Resource": "*"
}
]
}
The problem with aws:userid
Reading the docs about the key aws:userid we can find this key has the value given by role id:caller-specified-role-name,
where role id is the unique id of the role and the caller-specified-role-name is specified by the RoleSessionName parameter passed to the AssumeRole request.
So aws:userid has value like AIDAJQABLZS4A3QDU576Q:SomeNameYouGive. Because this, your condition never match arn:aws:sts::123456789012:assumed-role/role-for-grp-l2/myuser1234 and then user cannot assume that actions.
Using conditions another way
Assuming RoleSessionName is the user name, you can use conditions this way:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"lambda:InvokeFunction",
"lambda:InvokeAsync",
"lambda:ListVersionsByFunction",
"lambda:GetFunction",
"lambda:ListAliases"
],
"Resource": "arn:aws:lambda:*:123456789012:function:my-lambda-function",
"Condition": {
"StringLike": {
"aws:userid": "*:myuser1234"
}
}
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"lambda:ListFunctions",
"lambda:ListEventSourceMappings",
"lambda:ListLayers",
"lambda:ListLayerVersions"
],
"Resource": "*",
"Condition": {
"StringLike": {
"aws:userid": "*:myuser1234"
}
}
}
]
}
if you prefer, you may remove * wildcard getting role id using AWS CLI with the command:
aws iam get-role --role-name ROLE_NAME
and changing condition as follows:
"Condition": {
"StringEquals": {
"aws:userid": "ROLE_ID:myuser1234"
}
}
I want to execute a lambda function whenever an item gets uploaded on S3. My function was invoked but there seem to be access error. What is the mistake?
I have defined a role lambdas3. Its trusted entity is lambda. It has following policy called s3lambda
Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1509114309000",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::mybucketname"
]
},
{
"Sid": "Stmt1509114340000",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*:*:*"
]
}
]
}
This is the lambda function
var aws = require('aws-sdk');
var s3 = new aws.S3();
exports.handler = function(event,context){
var bucket = event.Records[0].s3.bucket.name;
var key = decodeURIComponent(
event.Records[0].s3.object.key.replace(/\+/g,''));
var params = {
Bucket:bucket,
Key:key
};
s3.getObject(params,function(err,data){
if(err){
console.log(err);
context.fail('Error getting object'+
key+' from bucket'+bucket);
}else{
context.succeed('hello '+data.Body);
}
});
};
The function takes lambdas3 role during execution.
You need to add /* at the Resource S3 ARN in GetObject policy. S3:GetObject works for S3’s object ARN. For instance:
arn:aws:s3:::mybucketname/*
If you want to give permission to all objects in the bucket then you have to give full permission ('*' in Resource). Please find the update policy below,
Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1509114309000",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::mybucketname/*"
]
},
{
"Sid": "Stmt1509114340000",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*:*:*"
]
}
]
}