I am writing an IAM role for a CI/CD user which deploys our Cloud Development Kit (CDK) app. The CDK app consists of lambda functions, Fargate etc. The problem is, that CDK does not allow me to specify all the roles it needs. Instead it creates some of then on its own.
Couple of examples:
- Each lambda function with log retention has another lambda created by CDK which sets log retention to the log group and log streams.
- CloudTrail event executing a step function needs a role with
states:StartExecution
permission.
CDK creates these roles automatically and also puts inline policies to them. Which forces me to give my CI/CD role permissions to create roles and attach policies. So if anybody gets access to the CI/CD user (for example if our GitHub credentials leak), the attacker could create new roles and give them admin permissions.
I tried creating all the roles myself in a separate stack and then using these roles in CDK app. But as I mentioned above (see the examples above), it's not possible everywhere...
I also tried IAM permission boundary for the deployer role, but I can't figure out how to limit permissions for iam:PutRolePolicy
. CDK essentially does the following:
According to AWS documentation, conditions are quite basic string comparisons. I need to be able to select, which actions are allowed in the policy document passed to iam:PutRolePolicy
.
This is a sample of my permission boundary allowing the principal to create roles and put role policies. See the condition comment.
permission_boundary = aws_iam.ManagedPolicy(
scope=self,
id='DeployerPermissionBoundary',
managed_policy_name='DeployerPermissionBoundary',
statements=[
aws_iam.PolicyStatement(
actions=['iam:CreateRole'],
effect=aws_iam.Effect.ALLOW,
resources=[f'arn:aws:iam::{core.Aws.ACCOUNT_ID}:role/my-project-lambda-role']
),
aws_iam.PolicyStatement(
actions=['iam:PutRolePolicy'],
effect=aws_iam.Effect.ALLOW,
resources=[f'arn:aws:iam::{core.Aws.ACCOUNT_ID}:role/my-project-lambda-role'],
conditions=Conditions([
StringLike('RoleName', 'Required-role-name'),
StringLike('PolicyName', 'Required-policy-name'),
StringEquals('PolicyDocument', '') # I want to allow only specified actions like logs:CreateLogStream and logs:PutLogEvents
])
)
]
)
deployer_role = aws_iam.Role(
scope=self,
id='DeployerRole',
assumed_by=aws_iam.AccountRootPrincipal(),
permissions_boundary=permission_boundary,
inline_policies={
'Deployer': aws_iam.PolicyDocument(
statements=[
aws_iam.PolicyStatement(
actions=['iam:PutRolePolicy'],
effect=aws_iam.Effect.ALLOW,
resources=[f'arn:aws:iam::{core.Aws.ACCOUNT_ID}:role/my-project-lambda-role']
),
...
...
]
)
}
)
What is the correct way of limiting the PutRolePolicy
to selected actions only? I want to allow logs:CreateLogStream
and logs:PutLogEvents
and nothing else.
I've been fighting with this for quite some time and I don't want to fall back to giving out more permissions than necessary. Thanks everyone in advance!