A Pulumi package for creating and managing Amazon Web Services (AWS) cloud resources with infrastructure-as-code.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Guide for implementing AWS Identity and Access Management (IAM) best practices in your Pulumi infrastructure code.
Grant only the permissions required to perform a task.
const role = new aws.iam.Role("app-role", {
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "lambda.amazonaws.com",
},
}],
}),
});
new aws.iam.RolePolicy("specific-permissions", {
role: role.id,
policy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Action: [
"s3:GetObject",
"s3:PutObject",
],
Resource: `${bucket.arn}/*`,
}],
}),
});For AWS services and EC2 instances, use IAM roles rather than embedding credentials.
const instanceRole = new aws.iam.Role("instance-role", {
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "ec2.amazonaws.com",
},
}],
}),
});
const instanceProfile = new aws.iam.InstanceProfile("instance-profile", {
role: instanceRole.name,
});
const instance = new aws.ec2.Instance("web-server", {
instanceType: "t3.micro",
ami: "ami-12345678",
iamInstanceProfile: instanceProfile.name,
});Create service-specific roles with managed policies.
const lambdaRole = new aws.iam.Role("lambda-role", {
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "lambda.amazonaws.com",
},
}],
}),
});
new aws.iam.RolePolicyAttachment("lambda-basic", {
role: lambdaRole.name,
policyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
});Enable secure access across AWS accounts.
const crossAccountRole = new aws.iam.Role("cross-account", {
assumeRolePolicy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
AWS: `arn:aws:iam::${trustedAccountId}:root`,
},
Condition: {
StringEquals: {
"sts:ExternalId": externalId,
},
},
}],
}),
});Use conditions for fine-grained access control.
const policy = new aws.iam.Policy("conditional-policy", {
policy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Action: "s3:*",
Resource: "*",
Condition: {
IpAddress: {
"aws:SourceIp": ["10.0.0.0/16"],
},
StringEquals: {
"aws:RequestedRegion": ["us-west-2", "us-east-1"],
},
},
}],
}),
});Attach policies directly to resources.
new aws.s3.BucketPolicy("bucket-policy", {
bucket: bucket.id,
policy: pulumi.all([bucket.arn, role.arn]).apply(([bucketArn, roleArn]) =>
JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Principal: {
AWS: roleArn,
},
Action: ["s3:GetObject"],
Resource: `${bucketArn}/*`,
}],
})
),
});const policy = new aws.iam.Policy("mfa-required", {
policy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Deny",
Action: "*",
Resource: "*",
Condition: {
BoolIfExists: {
"aws:MultiFactorAuthPresent": "false",
},
},
}],
}),
});Implement automatic credential rotation using Secrets Manager.
const secret = new aws.secretsmanager.Secret("db-credentials", {
name: "database-credentials",
});
const rotation = new aws.secretsmanager.SecretRotation("rotation", {
secretId: secret.id,
rotationLambdaArn: rotationLambda.arn,
rotationRules: {
automaticallyAfterDays: 30,
},
});Limit the maximum permissions a role can have.
const boundary = new aws.iam.Policy("boundary", {
policy: JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Action: [
"s3:*",
"dynamodb:*",
],
Resource: "*",
}],
}),
});
const role = new aws.iam.Role("bounded-role", {
assumeRolePolicy: "...",
permissionsBoundary: boundary.arn,
});const trail = new aws.cloudtrail.Trail("audit-trail", {
s3BucketName: auditBucket.id,
includeGlobalServiceEvents: true,
isMultiRegionTrail: true,
enableLogFileValidation: true,
});const alarm = new aws.cloudwatch.MetricAlarm("unauthorized-api-calls", {
name: "unauthorized-api-calls",
metricName: "UnauthorizedAPICalls",
namespace: "CloudTrailMetrics",
statistic: "Sum",
period: 300,
evaluationPeriods: 1,
threshold: 1,
comparisonOperator: "GreaterThanOrEqualToThreshold",
alarmActions: [snsTopic.arn],
});Install with Tessl CLI
npx tessl i tessl/npm-pulumi--aws