Cannot grant permission to EventBridge bus - amazon-iam

I am creating a custom bus in AWS EventBridge via CDK:
export class EventbridgeStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const targetCoreBus = new events.EventBus(this, 'TargetCoreBus', {
eventBusName: 'TargetCoreBus',
});
targetCoreBus.grantPutEventsTo(new iam.AccountPrincipal('1234567890'));
}
}
The bus is created fine, but I assumed the line
targetCoreBus.grantPutEventsTo(new iam.AccountPrincipal('1234567890'));
Would add policy to the bus that would allow specified account to put events into it. But it doesn't seem to do anything, nothing new is synthesized in the stack, no policy is added to the bus. Is it expected, am I doing something wrong?

grantPutEventsTo adds an inline, identity-based policy to the Grantee. For instance, targetCoreBus.grantPutEventsTo(MyLambda) would add a AWS::IAM::Policy to the Lambda's execution role.
You want to add the account principal to the Bus' resource-based policy. The CfnEventBusPolicy construct will do just that:
new events.CfnEventBusPolicy(this, 'CustomBusResoucePolicy', {
statementId: 'Cross-Account-Bus-20220509',
action: 'events:PutEvents',
principal: '123456789012',
eventBusName: targetCoreBus.eventBusName,
condition: {...},
});

Related

Accessing CDK Stack Resources

When creating a basic s3 resource with the following code
export class Test1Stack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'sampleBucket', {
versioned: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: true
});
}
}
Cdk creates the following resources:
AWS::S3::Bucket
AWS::S3::BucketPolicy
Custom::S3AutoDeleteObjects
AWS::IAM::Role
AWS::Lambda::Function
AWS::CDK::Metadata
I can access AWS::S3::Bucket AWS::S3::BucketPolicy properties by using
const s3 = new s3.Bucket(.......)
What object would give me access to the rest of the resources, for example if I'd like to overwrite the logical id for AWS::IAM::Role.
I imagine that I could create my own AWS::IAM::Role, AWS::Lambda::Function, AWS::CDK::Metadata and in this way I could use the same mechanism I am using for s3 to manipulate & override properties, but it is not what I am looking for.
I just want to be able to access the other resources at run time.
I have tried the properties from the constructor with no success.
I also understand that CDK does not recommend overriding resources.
You can access the bucket policy, assuming it got auto-created, and change its logical id like so:
const policy = bucket.policy!;
(policy.node.defaultChild as CfnBucketPolicy).overrideLogicalId("MyBucketPolicy")
As for the IAM Role related to autoDeleteObjects it is also possible but a little bit more brittle. There's a custom resource provider mini-framework used. This means that the labmda is shared between all Buckets in a given stack that use autoDeleteObjects.
Still, it is possible to get a hold of the lambda itself like so:
const provider = this.node.findChild('Custom::S3AutoDeleteObjectsCustomResourceProvider') as CustomResourceProvider
const lambda = provider.node.findChild('Handler') as CfnResource

A PolicyStatement used in an identity-based policy cannot specify any IAM principals error

let servicePrincipal: any = new iam.ServicePrincipal("lambda.amazonaws.com");
let policyDoc = new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: ["sts:AssumeRole"],
principals: [servicePrincipal],
effect: iam.Effect.ALLOW,
resources: ["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],
sid: ""
})
],
});
let accessRole: any = new iam.Role(this, 'git-access-role', {
assumedBy: servicePrincipal,
inlinePolicies: { policyDoc }
});
I'm creating a cdk lambda with a role that has AWSLambdaBasicExecutionRole but I get an error saying
A PolicyStatement used in an identity-based policy cannot specify any IAM principals
not quite sure...what does it mean and what should I do?
Looks like you're trying to generate the assume role policy with policyDoc. The assumedBy: servicePrincipal line will automatically generate the trust policy. If all you want to do is assign the lambda basic execution policy to the role, then it should look like this:
const accessRole = new iam.Role(this, 'git-access-role', {
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')]
});
If the lambda needs access to git as the construct id of the role seems to indicate then you can add those permissions as inline policies. But this code would create a role that is assumable by a lambda and it would have the most basic permissions a lambda needs to run.

How to limit SSM based on user starting the command

I have an EC2 that I am connecting to using the AWS Systems manager, the EC2 has a role of AmazonSSMManagedInstanceCore attached and I am able to use ssm startSession from the CLI.
Without adding permissions to the users themselves am I able to limit which users are allowed to initiate a session to the EC2s?
I have tried adding a second policy to the EC2s where I block access to ssm:StartSession (which works when I apply it with no condition) with a condition containing aws.userid and aws:ssmmessages:session-id but neither of these blocked access.
I am using federated users in this account.
Below is an example of the most recent policy attempting to block access to that specific email but not others (which does not work).
const myPolicy = new ManagedPolicy(this, "sendAndBlockPoicy", {
statements: [
new PolicyStatement({
sid: "AllowSendCommand",
effect: Effect.ALLOW,
resources: [`arn:aws:ec2:${Aws.REGION}:${Aws.ACCOUNT_ID}:*`],
actions: ["ssm:SendCommand"],
}),
new PolicyStatement({
sid: "blockUsers",
effect: Effect.DENY,
resources: ["*"],
actions: ["ssm:*", "ssmmessages:*", "ec2messages:*"],
conditions: {
StringLike: {
"aws:ssmmessages:session-id":
"ABCDEFGHIJKLMNOPQRSTUV:me#email.com",
},
},
}),
],
});
const managedSSMPolicy = ManagedPolicy.fromAwsManagedPolicyName(
"AmazonSSMManagedInstanceCore",
);
const role = new Role(this, 'ec2Role', {
assumedBy: new ServicePrincipal('ec2.amazonaws.com')
managedPolicies: [managedSSMPolicy, myPolicy ]
}

AWS CDK destroy fails to delete secret

I have a CDK script that creates an S3 bucket, VPC, and an RDS instance. Deploy is working, but the destroy fails with an error that my user is not authorized to secretsmanager:DeleteSecret.
I used the IAM policy testing tool to check and it passes. I am able to delete the secret via the UI. The CDK destroy command continues to fail though. Any thoughts?
CDK script:
class AcmeCdkStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// create a general purpose bucket for use with the app
new s3.Bucket(this, 'app-bucket', {
versioned: true
});
// create a vpc for our application
const vpc = new ec2.Vpc(this, 'app-vpc, {
cidr: "10.0.0.0/16",
});
// create a database instance
const db = new rds.DatabaseInstance(this, `app-db`, {
engine: rds.DatabaseInstanceEngine.POSTGRES,
instanceClass: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
vpc,
masterUsername: `dbadmin`,
deleteAutomatedBackups: false,
deletionProtection: false,
// https://github.com/aws/aws-cdk/issues/4036
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
}
}
const app = new cdk.App();
new AcmeCdkStack(app, 'app-stack;);
Error:
User: arn:aws:iam::0000000000:user/user#acme.com is not authorized to perform: secretsmanager:DeleteSecret on resource: arn:aws:secretsmanager:us-east-1:0000000000:secret:appdbdemoSecret0261-mjgIXOsp5rLL-HxFng1 (Service: AWSSecretsManager; Status Code: 400; Error Code: AccessDeniedException; Request ID: 000000000)
Based on the comments, the problem was that the CDK was using different credentials than expected. The solution was to use correct AWS_PROFILE.

How to add S3 BucketPolicy with AWS CDK?

I wanna translate this CloudFormation piece into CDK:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: S3BucketImageUploadBuffer
PolicyDocument:
Version: "2012-10-17"
Statement:
Action:
- s3:PutObject
- s3:PutObjectAcl
Effect: Allow
Resource:
- ...
Looking at the documentation here, I don't see a way to provide the policy document itself.
This is an example from a working CDK-Stack:
artifactBucket.addToResourcePolicy(
new PolicyStatement({
resources: [
this.pipeline.artifactBucket.arnForObjects("*"),
this.pipeline.artifactBucket.bucketArn],
],
actions: ["s3:List*", "s3:Get*"],
principals: [new ArnPrincipal(this.deploymentRole.roleArn)]
})
);
Building on #Thomas Wagner's answer, this is how I did this. I was trying to limit the bucket to a given IP range:
import * as cdk from '#aws-cdk/core';
import * as s3 from '#aws-cdk/aws-s3';
import * as s3Deployment from '#aws-cdk/aws-s3-deployment';
import * as iam from '#aws-cdk/aws-iam';
export class StaticSiteStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Bucket where frontend site goes.
const mySiteBucket = new s3.Bucket(this, 'mySiteBucket', {
websiteIndexDocument: "index.html"
});
let ipLimitPolicy = new iam.PolicyStatement({
actions: ['s3:Get*', 's3:List*'],
resources: [mySiteBucket.arnForObjects('*')],
principals: [new iam.AnyPrincipal()]
});
ipLimitPolicy.addCondition('IpAddress', {
"aws:SourceIp": ['1.2.3.4/22']
});
// Allow connections from my CIDR
mySiteBucket.addToResourcePolicy(ipLimitPolicy);
// Deploy assets
const mySiteDeploy = new s3Deployment.BucketDeployment(this, 'deployAdminSite', {
sources: [s3Deployment.Source.asset("./mysite")],
destinationBucket: mySiteBucket
});
}
}
I was able to use the s3.arnForObjects() and iam.AnyPrincipal() helper functions rather than specifying ARNs or Principals directly.
The assets I want to deploy to the bucket are kept in the root of my project directory in a directory called mysite, and then referenced via a call to s3Deployment.BucketDeployment. This can be any directory your build process has access to, of course.
The CDK does this a little differently. I believe you are supposed to use bucket.addToResourcePolicy, as documented here.
As per the original question, then the answer from #thomas-wagner is the way to go.
If anyone comes here looking for how to create the bucket policy for a CloudFront Distribution without creating a dependency on a bucket then you need to use the L1 construct CfnBucketPolicy (rough C# example below):
IOriginAccessIdentity originAccessIdentity = new OriginAccessIdentity(this, "origin-access-identity", new OriginAccessIdentityProps
{
Comment = "Origin Access Identity",
});
PolicyStatement bucketAccessPolicy = new PolicyStatement(new PolicyStatementProps
{
Effect = Effect.ALLOW,
Principals = new[]
{
originAccessIdentity.GrantPrincipal
},
Actions = new[]
{
"s3:GetObject",
},
Resources = new[]
{
Props.OriginBucket.ArnForObjects("*"),
}
});
_ = new CfnBucketPolicy(this, $"bucket-policy", new CfnBucketPolicyProps
{
Bucket = Props.OriginBucket.BucketName,
PolicyDocument = new PolicyDocument(new PolicyDocumentProps
{
Statements = new[]
{
bucketAccessPolicy,
},
}),
});
Where Props.OriginBucket is an instance of IBucket (just a bucket).