AWS SCP: Deny action "RunEC2" when you have 2 conditions - amazon-web-services

I don't undertand why my SCP is not working as I expected or how can I do this..
I want to block "Run EC2 instances" without a certain tag ONLY if the instance is not created by Data Pipeline.
I was testing diff options and I tried this:
{
"Sid": "Name",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"ec2:CreateVolume"
],
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:volume/*"
],
"Condition": {
"Null": {
"aws:RequestTag/cost_center": "true"
},
"StringNotEquals": {
"aws:CalledVia": [
"datapipeline.amazonaws.com"
]
}
}
}
Why doesn't it work?
This SCP always allows EC2 creation (by datapipeline and EC2 instances console without tags)

Related

AWS SCP , enforce tagging for EC2 and allow specific AWS Backup service role to restore

I have a tag enforcement scp that deny ec2 creation without CodeDomaine Tag except for AWS Backup service:
"Statement": [
{
"Sid": "DenyEC2CreationSCP1",
"Effect": "Deny",
"Action": [
"ec2:RunInstances"
],
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:volume/*"
],
"Condition": {
"Null": {
"aws:RequestTag/CodeDomaine": "true"
},
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:sts::*:assumed-role/AWSBackupDefaultServiceRole/AWSBackup-AWSBackupDefaultServiceRole"
]
}
}
},
I want to allow AWS backup service to restore when needed but i get this error:
DecodedMessage": "{\"allowed\":false,\"explicitDeny\":true,\"matchedStatements\":{\"items\":[{\"statementId\":\"DenyEC2CreationSCP1\",\"effect\":\"DENY\",\"principals\":{\"items\":[{\"value\":\"AROAY56UJVB4...\"}]},\"principalGroups\":{\"items\":[]},\"actions\":{\"items\":[{\"value\":\"ec2:RunInstances\"}]},\"resources\":{\"items\":[{\"value\":\"arn:aws:ec2:*:*:instance/*\"},{\"value\":\"arn:aws:ec2:*:*:volume/*\"}]},\"conditions\":{\"items\":[{\"key\":\"aws:PrincipalArn\",\"values\":{\"items\":[{\"value\":\"arn:aws:sts::*:assumed-role/AWSBackupDefaultServiceRole/*\"}]}},{\"key\":\"aws:RequestTag/CodeDomaine\",\"values\":{\"items\":[{\"value\":\"true\"}]}}]}}]},\"failures\":{\"items\":[]},\"context\":{\"principal\":{\"id\":\"AROAY56UJ...:AWSBackup-AWSBackupDefaultServiceRole\",\"arn\":\"arn:aws:sts::<accountID>:assumed-role/AWSBackupDefaultServiceRole/AWSBackup-AWSBackupDefaultServiceRole\"},\"action\":\"ec2:RunInstances\",\"resource\":\"arn:aws:ec2:eu-west-3:<accountID>:instance/*\",\"conditions\":{\"items\":[{\"key\":\"ec2:InstanceMarketType\",\"values\":{\"items\":[{\"value\":\"on-demand\"}]}},{\"key\":\"aws:Resource\",\"values\":{\"items\":[{\"value\":\"instance/*\"}]}},{\"key\":\"aws:Account\",\"values\":{\"items\":[{\"value\":\"<accountID>\"}]}},{\"key\":\"ec2:AvailabilityZone\",\"values\":{\"items\":[{\"value\":\"eu-west-3b\"}]}},{\"key\":\"ec2:ebsOptimized\",\"values\":{\"items\":[{\"value\":\"false\"}]}},{\"key\":\"ec2:IsLaunchTemplateResource\",\"values\":{\"items\":[{\"value\":\"false\"}]}},{\"key\":\"ec2:InstanceType\",\"values\":{\"items\":[{\"value\":\"t2.medium\"}]}},{\"key\":\"ec2:RootDeviceType\",\"values\":{\"items\":[{\"value\":\"ebs\"}]}},{\"key\":\"ec2:InstanceProfile\",\"values\":{\"items\":[{\"value\":\"arn:aws:iam::<accountID>:instance-profile/autodesk-dev\"}]}},{\"key\":\"aws:Region\",\"values\":{\"items\":[{\"value\":\"eu-west-3\"}]}},{\"key\":\"aws:Service\",\"values\":{\"items\":[{\"value\":\"ec2\"}]}},{\"key\":\"ec2:InstanceID\",\"values\":{\"items\":[{\"value\":\"*\"}]}},{\"key\":\"aws:Type\",\"values\":{\"items\":[{\"value\":\"instance\"}]}},{\"key\":\"ec2:Tenancy\",\"values\":{\"items\":[{\"value\":\"default\"}]}},{\"key\":\"ec2:Region\",\"values\":{\"items\":[{\"value\":\"eu-west-3\"}]}},{\"key\":\"aws:ARN\",\"values\":{\"items\":[{\"value\":\"arn:aws:ec2:eu-west-3:<accountID>:instance/*\"}]}}]}}}"
}
I tried many solutions to adjust the SCP conditions but no way!!
thanks
Resolved !
have to specify the role RNA and not the session RNA (ex : arn:aws:iam::*:role/OrganizationAdminRole)
"Statement": [
{
"Sid": "DenyEC2CreationSCP1",
"Effect": "Deny",
"Action": [
"ec2:RunInstances"
],
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:volume/*"
],
"Condition": {
"Null": {
"aws:RequestTag/CodeDomaine": "true"
},
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::*:role/service-role/AWSBackupDefaultServiceRole"
]
}
}
},

Deny AWS IAM User access to specific elastic beanstalk environments

I have a problem with restricting the access to AWS Elastic Beanstalk to specific environments.
The goal is to create a policy that allows an IAM user to access the complete elastic beanstalk service (including creating new apps and environments), but completely deny access to the production environment in a specific app.
What I've tried is this (mainly copied from here), but it doesn't seem to work apparently - the user just with this policy attached gets access to all of AWS like the root user:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticbeanstalk:UpdateApplicationVersion",
"elasticbeanstalk:CreateApplicationVersion",
"elasticbeanstalk:DeleteApplicationVersion"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"elasticbeanstalk:InApplication": [
"arn:aws:elasticbeanstalk:<region>:<account id>:environment/<app name>/<environment name>"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"elasticbeanstalk:DescribeAccountAttributes",
"elasticbeanstalk:AbortEnvironmentUpdate",
"elasticbeanstalk:TerminateEnvironment",
"rds:*",
"elasticbeanstalk:ValidateConfigurationSettings",
"elasticbeanstalk:CheckDNSAvailability",
"autoscaling:*",
"elasticbeanstalk:RequestEnvironmentInfo",
"elasticbeanstalk:RebuildEnvironment",
"elasticbeanstalk:DescribeInstancesHealth",
"elasticbeanstalk:DescribeEnvironmentHealth",
"sns:*",
"elasticbeanstalk:RestartAppServer",
"s3:*",
"cloudformation:*",
"elasticloadbalancing:*",
"elasticbeanstalk:CreateStorageLocation",
"elasticbeanstalk:DescribeEnvironmentManagedActions",
"elasticbeanstalk:SwapEnvironmentCNAMEs",
"elasticbeanstalk:DescribeConfigurationOptions",
"elasticbeanstalk:ApplyEnvironmentManagedAction",
"cloudwatch:*",
"elasticbeanstalk:CreateEnvironment",
"elasticbeanstalk:List*",
"elasticbeanstalk:DeleteEnvironmentConfiguration",
"elasticbeanstalk:UpdateEnvironment",
"ec2:*",
"elasticbeanstalk:RetrieveEnvironmentInfo",
"elasticbeanstalk:DescribeConfigurationSettings",
"sqs:*",
"dynamodb:CreateTable",
"dynamodb:DescribeTable"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:*"
],
"Resource": [
"arn:aws:iam::123456789012:role/aws-elasticbeanstalk-ec2-role",
"arn:aws:iam::123456789012:role/aws-elasticbeanstalk-service-role",
"arn:aws:iam::123456789012:instance-profile/aws-elasticbeanstalk-ec2-role"
]
},
{
"Effect": "Allow",
"Action": [
"elasticbeanstalk:DescribeEvents",
"elasticbeanstalk:DescribeApplications",
"elasticbeanstalk:AddTags",
"elasticbeanstalk:ListPlatformVersions"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"elasticbeanstalk:InApplication": [
"arn:aws:elasticbeanstalk:<region>:<account id>:environment/<app name>/<environment name>"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"elasticbeanstalk:AddTags",
"elasticbeanstalk:Describe*"
],
"Resource": [
"arn:aws:elasticbeanstalk:*::platform/*",
"arn:aws:elasticbeanstalk:*:*:environment/*/*",
"arn:aws:elasticbeanstalk:*:*:application/*",
"arn:aws:elasticbeanstalk:*::solutionstack/*",
"arn:aws:elasticbeanstalk:*:*:applicationversion/*/*",
"arn:aws:elasticbeanstalk:*:*:configurationtemplate/*/*"
],
"Condition": {
"StringNotEquals": {
"elasticbeanstalk:InApplication": [
"arn:aws:elasticbeanstalk:<region>:<account id>:environment/<app name>/<environment name>"
]
}
}
}
]
}
The page your're referring is for restricting specific EB with applications not for envs.
This doc says about condition keys for Elastic Beanstalk actions,
InApplication:
Specifies the application that contains the resource
that the action operates on.
FromEnvironment:
Specifies an environment as a dependency or a constraint on an input
parameter.
... you can see the explanations and examples more.
The bottom line is that changing "elasticbeanstalk:InApplication" to "elasticbeanstalk:FromEnvironment" would work.

Deployment group's ECS service must be configured for a CODE_DEPLOY deployment controller

I've encountered following error when I'm trying to create Deployment Group for ECS Cluster in Code Deploy. I've created IAM that based on CodeDeploy ECS and its policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"ecs:DescribeServices",
"ecs:CreateTaskSet",
"ecs:UpdateServicePrimaryTaskSet",
"ecs:DeleteTaskSet",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:ModifyListener",
"elasticloadbalancing:DescribeRules",
"elasticloadbalancing:ModifyRule",
"lambda:InvokeFunction",
"cloudwatch:DescribeAlarms",
"sns:Publish",
"s3:GetObject",
"s3:GetObjectMetadata",
"s3:GetObjectVersion"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"iam:PassRole"
],
"Effect": "Allow",
"Resource": "*",
"Condition": {
"StringLike": {
"iam:PassedToService": [
"ecs-tasks.amazonaws.com"
]
}
}
}
]
}
Please let me know when I made mistake?
If you are using CodeDeploy, your ECS service has to be defined so that
it uses Blue/Green code deployments rather than Rolling Updates:
HTH!
Also if you are using terraform you can simply fix it by add this to aws_ecs_service:
deployment_controller {
type = "CODE_DEPLOY"
}

How to restrict access specific ssm document can run only in specific ec2 instance?

I am having the requirement of creating the policy that will have access to the custom created ssm document only can run in the specified EC2 instance.
I have tried policy something like this but it is not sufficient to control the document to be run on the instance.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2messages:DeleteMessage",
"ec2messages:GetEndpoint",
"ec2messages:FailMessage",
"ec2messages:AcknowledgeMessage",
"ec2messages:SendReply",
"ec2messages:GetMessages"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssm:UpdateInstanceInformation",
"ssm:UpdateAssociationStatus",
"ssm:ListInstanceAssociations",
"ssm:ListAssociations",
"ssm:UpdateInstanceAssociationStatus"
],
"Resource": [
"arn:aws:ssm:us-east-1:xxxxxxxxxx:document/xxxxxxxxxx",
"arn:aws:ec2:us-east-1:xxxxxxxxxx:instance/*"
]
}
]
}
Is this doable ?
Help is much appreciated. Thanks

Mandatory tagging when launching EC2 instance

In AWS, is there a way to force an IAM user to tag the instance he/she is about to launch? It doesn't matter what the value is. I want to make sure it is correctly tagged so that long running instances can be properly identified and the owner notified. Currently tagging is optional.
What I do currently is to use CloudTrail and identify the instances with their IAM users. I do not like it because it is an extra work to run the script periodically and CloudTrail has only 7 days worth of data. It would be nice if AWS has an instance attribute for owner.
Using keypairs to identify the owners is not a viable solution in our case. Anyone faced this problem before and how did you tackle it?
One way: Don't give them IAM permissions to launch boxes. Instead, have a web service that allows them to do it. (Production should be fully automated anyway). When they use your service, you can enforce all the rules you want. Yes, it's quite a bit of work, so not for everybody.
Currently tagging is optional.
It's worse than that. Tagging requires a 2nd API call, so even when using the API, things can launch without tags because of a hiccup.
I resolved this by using AWS Lambda. When CloudTrail creates an object in S3, it triggers an event that cause a Lambda function to execute. The Lambda function then parses the S3 object and creates the tag. There is a lag of ~2 mins but the solution works perfectly.
As #helloV mentions, this is possible by using AWS CloudTrail logs (once properly enabled) and AWS Lambda. I was able to accomplish this with the following code running in a python Lambda function:
s3 = boto3.client('s3')
ec2 = boto3.client(service_name='ec2', aws_access_key_id=aws_key, aws_secret_access_key=aws_secret_key)
def lambda_handler(event, context):
# Get the object from the event and show its content type
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
try:
response = s3.get_object(Bucket=bucket, Key=key)
compressed_file = StringIO.StringIO()
compressed_file.write(response['Body'].read())
compressed_file.seek(0)
decompressed_file = gzip.GzipFile(fileobj=compressed_file, mode='rb')
successful_tags = 0;
json_data = json.load(decompressed_file)
for record in json_data['Records']:
if record['eventName'] == 'RunInstances':
instance_user = record['userIdentity']['userName']
instances_set = record['responseElements']['instancesSet']
for instance in instances_set['items']:
instance_id = instance['instanceId']
ec2.create_tags(Resources=[instance_id], Tags=[{'Key':'Owner', 'Value':instance_user}])
successful_tags += 1
return 'Tagged ' + str(successful_tags) + ' instances successfully'
except Exception as e:
print(e)
print('Error tagging object {} from bucket {}'.format(key, bucket))
raise e
Check out the capitalone.io/cloud-custodian open source project -- it has the ability to enforce policies like this
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GrantIAMPassRoleOnlyForEC2",
"Action": [
"iam:PassRole"
],
"Effect": "Allow",
"Resource": [
"arn:aws:iam::*:role/ec2tagrestricted",
"arn:aws:iam::*:role/ec2tagrestricted"
],
"Condition": {
"StringEquals": {
"iam:PassedToService": "ec2.amazonaws.com"
}
}
},
{
"Sid": "ReadOnlyEC2WithNonResource",
"Action": [
"ec2:Describe*",
"iam:ListInstanceProfiles"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "ModifyingEC2WithNonResource",
"Action": [
"ec2:CreateKeyPair",
"ec2:CreateSecurityGroup"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "RunInstancesWithTagRestrictions",
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": [
"arn:aws:ec2:us-east-1:*:instance/*",
"arn:aws:ec2:us-east-1:*:volume/*"
],
"Condition": {
"StringEquals": {
"aws:RequestTag/test": "${aws:userid}"
}
}
},
{
"Sid": "RemainingRunInstancePermissionsNonResource",
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": [
"arn:aws:ec2:us-east-1::image/*",
"arn:aws:ec2:us-east-1::snapshot/*",
"arn:aws:ec2:us-east-1:*:network-interface/*",
"arn:aws:ec2:us-east-1:*:key-pair/*",
"arn:aws:ec2:us-east-1:*:security-group/*"
]
},
{
"Sid": "EC2RunInstancesVpcSubnet",
"Effect": "Allow",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:us-east-1:*:subnet/*",
"Condition": {
"StringEquals": {
"ec2:Vpc": "arn:aws:ec2:us-east-1:*:vpc/vpc-8311b8f9"
}
}
},
{
"Sid": "EC2VpcNonResourceSpecificActions",
"Effect": "Allow",
"Action": [
"ec2:DeleteNetworkAcl",
"ec2:DeleteNetworkAclEntry",
"ec2:DeleteRoute",
"ec2:DeleteRouteTable",
"ec2:AuthorizeSecurityGroupEgress",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupEgress",
"ec2:RevokeSecurityGroupIngress",
"ec2:DeleteSecurityGroup",
"ec2:CreateNetworkInterfacePermission",
"ec2:CreateRoute",
"ec2:UpdateSecurityGroupRuleDescriptionsEgress",
"ec2:UpdateSecurityGroupRuleDescriptionsIngress"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:Vpc": "arn:aws:ec2:us-east-1:*:vpc/vpc-8311b8f9"
}
}
},
{
"Sid": "AllowInstanceActionsTagBased",
"Effect": "Allow",
"Action": [
"ec2:RebootInstances",
"ec2:StopInstances",
"ec2:TerminateInstances",
"ec2:StartInstances",
"ec2:AttachVolume",
"ec2:DetachVolume",
"ec2:AssociateIamInstanceProfile",
"ec2:DisassociateIamInstanceProfile",
"ec2:GetConsoleScreenshot",
"ec2:ReplaceIamInstanceProfileAssociation"
],
"Resource": [
"arn:aws:ec2:us-east-1:347612567792:instance/*",
"arn:aws:ec2:us-east-1:347612567792:volume/*"
],
"Condition": {
"StringEquals": {
"ec2:ResourceTag/test": "${aws:userid}"
}
}
},
{
"Sid": "AllowCreateTagsOnlyLaunching",
"Effect": "Allow",
"Action": [
"ec2:CreateTags"
],
"Resource": [
"arn:aws:ec2:us-east-1:347612567792:instance/*",
"arn:aws:ec2:us-east-1:347612567792:volume/*"
],
"Condition": {
"StringEquals": {
"ec2:CreateAction": "RunInstances"
}
}
}
]
}
This policy restricts a user to Launch an ec2 instance only if the Tag key is test and value is the variable ${aws.userid} different values can be found here
Notable things
This does not restrict the number of ec2 instances a user can launch
User can change the tag of existing instances tag and gain control
We can use TagKeys https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html#access_tags_control-tag-keys to tackle the above two situations but I did not do it
Attach this policy to the user or group to prevent them from launching an instance without tagging it:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/Owner": "true"
}
}
}
}
When the user tries to launch an instance, they'll get an error:
(If anyone knows a way to display a cleaner error message, please let us know in the comments.)
Decode the error like so:
aws sts decode-authorization-message \
--encoded-message <encoded-message> \
--query DecodedMessage --output text | jq '.'
Part of the (giant) response is as follows:
{
"allowed": false,
"explicitDeny": true,
"matchedStatements": {
"items": [
{
"statementId": "",
"effect": "DENY",
"principals": {
"items": [
{
"value": "AIDATDOMLI3YFAYEBFGSO"
}
]
},
"principalGroups": {
"items": []
},
"actions": {
"items": [
{
"value": "ec2:RunInstances"
}
]
},
"resources": {
"items": [
{
"value": "*"
}
]
},
"conditions": {
"items": [
{
"key": "aws:RequestTag/Owner",
"values": {
"items": [
{
"value": "true"
}
]
}
}
]
}
}
]
}
}
It shows that the launch failed because the Owner tag is missing.
Do you use/require userdata scripts at launch time? We use that script process to properly tag each instance as it is launched.
We burn a support script into the AMI that is launched by the userdata, and parses the command line for parameters. These parameters are then used to create tags for the newly launched instances.
For manual launches, the user must load the correct userdata script for this to work. But from automated launching script, or from a properly configured Launch Configuration in an Auto-scaling Group, it works perfectly.
<script>
PowerShell -ExecutionPolicy Bypass -NoProfile -File c:\tools\server_userdata.ps1 -function Admin -environment production
</script>
Using this method, an instance launched with that userdata will be automatically tagged with the Function and Environment tags.