This project implements a solution to automate the process of validating and deploying IAM Roles in AWS Accounts with appropriate protection in place.
This repository contains the implementation of the pattern described in Validate and deploy IAM Roles in AWS Accounts using CodePipeline, Access Analyser and CloudFormation Macros.
Development teams need to create IAM Roles in AWS Accounts where their applications will run. Security team needs to make sure that the IAM Roles don't introduce any threat for the company. So, in order to avoid the creation of unsafe IAM roles, companies usually centralize the creation of IAM roles in a single team that evaluates the dev team request before allowing them to deploy their roles. This manual evaluation can break the deployment flow, since dev teams need to wait for the security team aprove or reprove their request.
The solution presented here implements a deployment pipeline (RolesPipeline) that leverages IAM Access Analyzer to validate grammar and best practices of IAM policies that will be attached to the roles and CloudFormation (CF) to deploy the roles.
CloudFormation template, applied during the deployment stage, makes use of a Macro that transforms the repo's files into valid IAM resources and also includes a PermissionsBoundary to the roles.
With this solution in place, dev team has autonomy to create roles without waiting for external approvals and security team can trust on IAM Access Analyzer and PermissionsBoundary to limit the permissions of the roles created by the dev team.
lambda.roles_macro.py
contains the CloudFormation Macro implementation (step 4) to tranform json files into CloudFormationAWS::IAM::Role
resources.
For more information about how the solution works, see the pattern related to this repository.
The roles-example
folder contains a sample of how the repository connected to the RolesPipeline should be structured.
File structure
The root directory of the pipeline repository must have a file called roles.json
. This file is a map, whose keys are the role's name and the value is an object with the role definition:
{
"first-role-name": {
"Service": [
"ec2.amazonaws.com"
],
"Path": "/",
"Policies": [policy-file1, policy-file2],
"Description": "",
"MaxDuration": 900
},
"second-role-name": {
...
},
// can contains severals roles
}
Service and Policies are mandatory attributes for each role definition.
Attribute Policies must contain an array of json file paths (where it is the policies that must be attached to roles).
Example:
+— roles.json
+— policy-ec2/
+— policy1.json
+— policy2.json
+— policy-lambda/
+— policy1.json
+— policy2.json
roles.json:
{
"role1-ec2": {
"Service": ["ec2.amazonaws.com"],
"Path": "/",
"Policies": [
"policy-ec2/policy1.json", "policy-ec2/policy2.json"
]
},
"role2-lambda": {
"Service": ["lambda.amazonaws.com"],
"Path": "/",
"Policies": [
"policy-lambda/policy1.json", "policy-lambda/policy2.json"
]
}
}
Previous files will be tranformed in the following CF Template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"role1Dashec2Resource": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "policy1",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:Describe*",
"cloudformation:List*",
"cloudformation:Get*"
],
"Resource": "*"
}
]
}
},
{
"PolicyName": "policy2",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:Describe*",
"cloudformation:List*",
"cloudformation:Get*"
],
"Resource": "*"
}
]
}
}
]
}
},
"role2DashlambdaResource": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "policy1",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:Describe*",
"cloudformation:List*",
"cloudformation:Get*"
],
"Resource": "*"
}
]
}
},
{
"PolicyName": "policy2",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudformation:Describe*",
"cloudformation:List*",
"cloudformation:Get*"
],
"Resource": "*"
}
]
}
}
]
}
}
}
}
Follow the steps bellow:
-
Before starting the deployment, make sure that you have AWS CLI, AWS SAM installed. Also, make sure you have AWS CLI with a default profile configured to the AWS Account you want to do the tests.
-
Package and deploy the solution to your AWS Account.
$> make deploy bucket=<bucket-name>
bucket-name
where AWS SAM will pack the lambda and cloudformation template.
If this command runs without error, you should have all solution deployed on you account.
- Check if deployment occured successfully
$> aws codepipeline get-pipeline --name RolesPipeline
Should return a json response with the pipeline definition.
- Clone roles-pipeline-repo
- Configure Git credentials for accessing CodeCommit in your account using this link
- Runs
$> aws codecommit get-repository --repository-name roles-pipeline-repo
- Get the repo url from
cloneUrlHttp
orcloneUrlSsh
- Runs
$> git clone <repo-url>
-
Create a file structure similar to
roles-example
folder. -
Commit and push the modification
-
Check the deployment progress accessing the AWS CodePipeline web console.
-
Empty the buckets used by the solution before running destroy command. Bucket names begin with
rolespipelinestack
-
Delete the CloudFormation RolesStack
-
Destroy the RolesPipeline
$> make destroy
See CONTRIBUTING for more information.
This library is licensed under the MIT-0 License. See the LICENSE file.