Securing the framework¶
To increase the security in your environment and enable traceability we recommend you to apply the following configuration:
Applying an s3 bucket policy to
attini-deployment-origin-${Region}-${AccountId}
bucket.Applying an s3 bucket policy to
attini-artifact-store-${Region}-${AccountId}
bucket.Securely configure the Install Attini Framework CloudFormation stack.
Configure AWS CloudTrail data events on Attini resources (s3 and lambda).
Bucket policies¶
By creating specific bucket policies on the attini-deployment-origin
and the attini-artifact-store
bucket you can
ensure that you don’t give this access to anyone by mistake.
You should also consider adding a restriction on the s3:PutBucketPolicy
API for these buckets so that
no one can tamper with your security configuration.
Warning
By restricting access to the s3:PutBucketPolicy
API you can lock yourself out of your buckets so be careful. You
should never rely on AWS SSO Roles to manage this API because those roles might be replaces.
Attini deployment origin bucket¶
Anyone that have s3:PutObject
access to the attini-deployment-origin
bucket will be able to do
deployments which is a very high privilege.
The attini-deployment-origin bucket policy need to allow the following:
Give access to anyone that need to start a deployment, ex your build server or your DevOps personal.
Allow the Attini framework to read the distribution (s3 object)
Deployment origin bucket policy example:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictDeploymentAccess",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::attini-deployment-origin-${Region}-${AccountId}/*",
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": "{ARN of the user or role that should be able to deploy}"
}
}
}
]
}
Attini artifact store bucket¶
Anyone that have s3:PutObject
access to attini-artifact-store
bucket will be able to
replace files that will be used in the next re-run of a deployment, that way they could tamper with
your cloud environment. To manage this risk, it’s important to have cloud trail object level logging
activated on the attini-artifact-store
bucket and use least privilege IAM roles for your deployment steps.
If you have any distributions with sensitive information, you can also use bucket policies to restrict read access to specific paths in the attini buckets.
Artifact store policy example:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictAccessToArtifactStore",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::attini-artifact-store-${Region}-${AccountId}/*",
"Condition": {
"ArnNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::${AccountId}:role/attini/attini-init-deploy-lambda-role-${Region}"
}
}
}
]
}
Bucket policies CloudFormation example¶
AWSTemplateFormatVersion: 2010-09-09
Description: Bucket policies for the Attini Framework
Resources:
AttiniDeploymentOriginBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Sub attini-deployment-origin-${AWS::Region}-${AWS::AccountId}
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: RestrictDeploymentAccess
Principal: "*"
Action:
- "s3:PutObject"
Effect: Deny
Resource:
- !Sub arn:aws:s3:::attini-deployment-origin-${AWS::Region}-${AWS::AccountId}/*
Condition:
ArnNotLike:
!Sub aws:PrincipalArn: arn:aws:iam::${AWS::AccountId}:role/aws-reserved/sso.amazonaws.com/${AwsSsoRegion}/AWSReservedSSO_AdministratorAccess_*
# Fill in any IAM Role or User that should be able to do deployments
AttiniArtifactStoreBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Sub attini-artifact-store-${AWS::Region}-${AWS::AccountId}
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: RestrictAccessToArtifactStore
Principal: "*"
Action:
- "s3:PutObject"
Effect: Deny
Resource:
- !Sub arn:aws:s3:::attini-artifact-store-${AWS::Region}-${AWS::AccountId}/*
Condition:
ArnNotEquals:
aws:PrincipalArn: !Sub arn:aws:iam::${AWS::AccountId}:role/attini/attini-init-deploy-lambda-role-${AWS::Region}
# Fill in any IAM Role or User that should be able to manipulate files in the artifact store
How can I configure the S3 Bucket policies using AWS SSO Roles?¶
If you use AWS SSO, the underlying AWS IAM roles have unpredictable names making it hard to configure. AWS SSO also replaces the roles sometimes meaning that you should never use AWS SSO Roles as a Principal in any IAM policy because that trust can be broken and sometimes hard to restore.
To reference an AWS SSO Role in an IAM/S3 Policy in a maintainable manner you have 2 alternatives:
Use an ArnLike/ArnNotLike condition in your bucket policy.
Use Attini’s Open Source project that will provide the SSO Role arn via AWS ParameterStore.
ArnLike/ArnNotLike condition¶
Warning
AWS have in no way guaranteed that the naming convention for these roles, so there is a risk that they will change and break your permission configuration. If you are worried about this, please see the second option (Attini’s SSO Role name mapper).
Hint: To get the current IAM role arn you are using you can find your current AWS role in the IAM console.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RestrictDeploymentAccess",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::attini-deployment-origin-${Region}-${AccountId}/*",
"Condition": {
"ArnNotLike": {
"aws:PrincipalArn": "arn:aws:iam::${AccountId}:role/aws-reserved/sso.amazonaws.com/${SsoRegion}/AWSReservedSSO_${PermissionSetName}_*"
}
}
}
]
}
Attini’s SSO Role name mapper¶
As a workaround, we built an open-source project that will populate AWS SSM ParameterStore with the arn of the SSO roles. Find more information in the GitHub repository.
Warning
If you configure the s3:PutBucketPolicy
API in a bucket policy, make sure you always
have a backup Principal that can update the BucketPolicy if the AWS SSO role is replaced.
When you have all the AWS SSO roles a with predictable names in AWS SSM ParameterStore you can use CloudFormations SSM ParameterStore integration to automatically configure your bucket policy.
Warning
Anyone that can update these parameters use can tamper with your security configuration.
Securely configure the attini-setup CloudFormation stack and my deployment plans.¶
This chapter is about configuring the attini-setup CloudFormation stack and the underlying Attini DeploymentPlans <api-reference_attini-deployment-plan>.
When configuring a CI/CD system you often have a “catch 22” situation. You need certain resources (in Attini’s case it is IAM roles) for the CI/CD system to work, but you want to use the CI/CD system to create the resources you need.
To work around this you can do one of the following:
Create the resources yourself, then deploy the Install Attini Framework CloudFormation stack using the IAM roles you just created.
Install Attini Framework with high privileges, then use Attini to create and configure the required resources for you. After that you can re-configure the Attini Framework with your least privilege IAM roles.
Keep in mind that you can reconfigure attini-setup at any time so you can adjust add or remove privileges as needed.
InitDeployRole¶
InitDeploy Role is configured by the CreateInitDeployDefaultRole
and InitDeployRoleArn
parameters in the attini-setup
These 2 parameters configure the access for the InitDeploy. Meaning the CloudFormation stack that Attini automatically creates when a distribution is deployed. This CloudFormation stack is intended to create CI/CD resources like (Attini deployment plans, AWS CodeBuild Projects, CloudFormation IAM stack roles etc).
Note
If you set the “CreateInitDeployDefaultRole”=”true” attini-setup will create a default role with high privileges to make it easy to get started with the Attini Framework, however, in production environments we recommend that you create your own InitDeploy Role. Then you can control which resources can be created by the Attini InitDeploy.
If you create an IAM Role and configure the InitDeployRoleArn parameter, this role have to:
Be a AWS Lambda service role. Assume role document:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Add whatever privileges you might need for your deployment resources (to create Attini deployment plans this role needs permission to create and update AWS StepFunction and CloudWatch events).
Note
attini-setup will add an least privilege inline IAM policy to your InitDeploy Role that will enable it to work with the Attini Framework.
DeploymentPlan Role¶
The DeploymentPlan Role is configured via the RoleArn parameter in the Attini::Deploy::DeploymentPlan resource. By configuring this role you can allow the Attini DeploymentPlan to do anything you might need in AWS while sticking to the least privilege principal.
The “CreateDeploymentPlanDefaultRole” parameter in the attini-setup sets up a default role for the DeploymentPlans with quite broad permission to make the Attini Framework a bit easier to work with. In production environments we recommend to set “CreateDeploymentPlanDefaultRole”=”false”
ExecutionRole¶
The ExecutionRole is configured via the ExecutionRoleArn parameter in the Attini::Deploy::DeploymentPlan AttiniCfn resource. By configuring this role you can allow the AttiniCfn step to do anything you might need in AWS while sticking to the least privilege principal.
These ExecutionRole permissions are automatically transferred to the AWS CloudFormation stack that the AttiniCfn is deploying unless you also specify a StackRoleArn, then CloudFormation will update its resources with the StackRole credentials. So if the StackRoleArn is configured, the ExecutionRole will only need permissions to create/update the CloudFormation stack.
Configuring the ExecutionRole you can also deploy CloudFormation stacks to other AWS Accounts, find more info here.
StackRole¶
The StackRole is configured via the StackRoleArn parameter in the Attini::Deploy::DeploymentPlan AttiniCfn resource. By configuring this role you can apply a AWS CloudFormation service role.
To allow a Attini DeploymentPlan to apply a stack role you have to configure AwsServiceRolesContainsString
parameter
in the attini-setup correctly. If you configure an ExecutionRole in combination with
StackRole, the ExecutionRole will need iam:PassRole
permission to the StackRole.
StackRoles can be a powerful tool if you ever need to give out granular access to different members of your organization.
For example, let’s say that you have a development team in your organization that should be able
to update a few specific ECS Services. Instead of giving the developers esc:UpdateService
permission,
you can give them cloudformation:UpdateStack
permission and then control which stacks via
AWS IAM Resource or Condition configuration.
Then you give the StackRole Permissions to do esc:UpdateService
. This lets
your staff escalate their own privileges in a controlled way.
If you have a few CloudFormation Parameters that you want to be manually configured/maintained, please see fallback configuration in the CloudFormation ParameterValue config.
Warning
This is actual privilege escalation which comes with certain risks. If the StackRole for example
have the permission to do iam:UpdateRole
, nothing will stop it from giving the IAM Role
AdministerAccess and give a potential hacker the ability to assume the role. So please
be careful with IAM permission on StackRoles.
A way to work around the issue is with IAM Permissions Boundarys
in combination with IAM Condition key iam:PermissionsBoundary
.
ExecutionRole vs StackRole¶
From an Attini deployment perspective, it does not matter if ExecutionRoles or StackRoles are being used, however, StackRoles comes with extra capability’s which often create unnecessary complexity.
Therefore Attini recommends you to use ExecutionRoles as default and only apply a StackRoles when you have a specific use case for it.
Activate CloudTrail¶
Activating CloudTrail on the Attini resources gives you a much better audibility and its therefore highly recommend. If you have activated data events on all S3 buckets and Lambdas you are already done.
Warning
Be aware that data events comes with an additional cost
We at Attini strongly recommend that you activate CloudTrail data events on the following Attini resources to give your proper traceability:
The
attini-deployment-origin
S3 bucketThe
attini-artifact-store
S3 bucketThe
attini-action
LambdaThe
attini-init-deploy
LambdaThe
attini-auto-update
LambdaThe
attini-step-guard
Lambda
This will log any new deploys which is critical information if you are looking for an intruder, it will also trace any tampering with your current artifacts or trigger of Lambda functions.
Note
These data events does not appear in the normal cloud trail logs, you have to find them in the logs shipped to s3.
Minimum recommend CloudTrail logging:
[
{
"name": "Minimum logs",
"fieldSelectors": [
{
"field": "eventCategory",
"equals": [
"Data"
]
},
{
"field": "resources.type",
"equals": [
"AWS::S3::Object"
]
},
{
"field": "resources.ARN",
"startsWith": [
"arn:aws:s3:::attini-deployment-origin",
"arn:aws:s3:::attini-artifact-store",
"arn:aws:s3:::prod-attini-support-logs",
"arn:aws:s3:::acc-attini-support-logs"
]
}
]
},
{
"name": "Lambda events",
"fieldSelectors": [
{
"field": "eventCategory",
"equals": [
"Data"
]
},
{
"field": "resources.type",
"equals": [
"AWS::Lambda::Function"
]
},
{
"field": "resources.ARN",
"endsWith": [
"attini-action",
"attini-init-deploy",
"attini-auto-update",
"attini-step-guard"
]
}
]
}
]
Security considerations¶
Administrating our IT environments with a high level of automation brings many advantages, and done right it can increase your security by:
Decreasing the privileges your staff need in their day to day activities
Easier to maintain a minimum privileges access model
Easier to implement tests that can find vulnerabilities
Easier to update and patch the underlying infrastructure
Easier to implement and maintain security resources like Alarms and AWS Config Rules
The drawback to this is that the tools you need to Administer you IT environment needs Admin access to your resources, which of course is associated with risks.
Anyone that can put distributions (s3 files) into attini-deployment-origin bucket can use the framework to deploy new IAM roles, which means that in the worst case scenario someone can deploy a new admin role that only they can assume and therefore escalate their own privileges.
Warning
The possibility to escalate privileges is always a risk you take when you automate the creation and updates of IAM entities (Roles, Users, and Policy). For this reason, you have to be very careful when you use deployment tools for IAM configuration, ex CloudFormation stack roles.
For example, if you give a CloudFormation stack IAM privileges and then give someone access to the “CloudFormation:StackUpdate” API, that person can give themselves AdministratorAccess by creating or updating a role that is created by the CloudFormation stack. For this reason we at Attini always recommend you to have separate CloudFormation stacks for security-related resources (IAM, KMS, EC2 Security groups etc) so that you can easily separate access to them.
Another Recommended way to avoid escalation of privileges is AWS Permissions boundaries.