I need some help related to creating AWS policies.
I need a policy linked to an EC2 instance to be able to give only a get-parameters-by-path
to a specific parameter in AWS SSM parameter store, without being able to change anything like Delete
, Create
, etc and should only be able to get the values.
This policy specificity will be given through tags.
Here's my policy I'm trying to use:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ssm:*"],
"Resource": ["*"]
},
{
"Effect": "Deny",
"Action": [
"ssm:PutParameter",
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:DeleteParameter",
"ssm:GetParameterHistory",
"ssm:DeleteParameters",
"ssm:GetParametersByPath"
],
"Resource": ["*"],
"Condition": {
"StringNotEquals": {
"ssm:resourceTag/env": "development-1"
}
}
}
]
}
Using the AWS Policy Simulator it informs you that when trying to View
, Create
, Modify
, Delete
Parameters with "ssm:resourceTag/env": "development-2"
a denial message is informed, while other projects with "ssm:resourceTag/env": "development-1"
it is possible to modify, view, etc.
However, when tying the same policy to an EC2 instance, the policy blocks any of the actions added in Deny.
EC2 Informed Messages:
/development-1/project-1
aws --region us-east-2 ssm get-parameters-by-path --path /development-1/project-1/ --recursive --with-decryption --output text --query "Parameters[].[Value]"
An error occurred (AccessDeniedException) when calling the GetParametersByPath operation: User: arn:aws:sts::111111111:assumed-role/rule-ec2/i-11111111111 is not authorized to perform: ssm:GetParametersByPath on resource: arn:aws:ssm:us-east-2:11111111111:parameter/development-1/project-1/ with an explicit deny
/development-2/project-2
aws --region us-east-2 ssm get-parameters-by-path --path /development-2/project-2/ --recursive --with-decryption --output text --query "Parameters[].[Value]"
An error occurred (AccessDeniedException) when calling the GetParametersByPath operation: User: arn:aws:sts::11111111111:assumed-role/rule-ec2/i-11111111111 is not authorized to perform: ssm:GetParametersByPath on resource: arn:aws:ssm:us-east-2:11111111111:parameter/development-2/project-2/ with an explicit deny
Tags used:
key=value
/development-1/project-1
:
env=development-1
/development-2/project-2
:
env=development-2
What am I doing wrong?
You can't set a condition key based on the tag of the parameter for any of the ssm:GetParameter*
IAM actions because the API doesn't (currently) support condition keys.
Instead you can restrict by the ARN of the parameter and in general the practice with SSM parameter store is to use a hierarchical path to the parameters to allow for you to restrict access via IAM and then optionally wildcarding where you are happy for things to have anything under that path.
So a common pattern might be to have some structure that looks something like this:
/production/foo-service/database/password
/production/foo-service/bar-service/api-key
/production/bar-service/database/password
/production/bar-service/foo-service/api-key
/development/foo-service/database/password
/development/foo-service/bar-service/api-key
/development/bar-service/database/password
/development/bar-service/foo-service/api-key
Then for your foo-service running in production you give it an IAM role with the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ssm:GetParameter*"],
"Resource": ["arn:aws:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter/production/foo-service/*"]
}
]
}
This will allow the foo-service in production to then access both of /production/foo-service/database/password
and /production/foo-service/bar-service/api-key
but won't allow access to any of the other parameters or the ability to modify or delete the parameters.
As mentioned in @Marcin's answer, you don't need to add a deny statement to your IAM policy here because the default for IAM is to deny unless things have explicitly been given an allow statement.
The exception to this would be if you are doing very complex things where you want to give mostly access to a wide range of things but then block a small subset of things. This blog post talks about how the default ReadOnlyAccess
policy is too permissive for their organisation so they restrict access with a deny statement on things they don't want to give such open access to. They could also go the opposite way and never use that AWS managed policy and instead have to maintain a very broad set of actions across a lot of services themselves which might be considered safer but also potentially a lot of work.
You are using Deny
to ssm:GetParametersByPath
, so it will always be denied. Deny always takes a priority over any allow.
But in your case, since its instance profile, your policy doesn't have to be that complex. By default, everything is implicitly denied, so you only need explicit allow:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ssm:GetParametersByPath"],
"Resource": ["*"]
}
]
}
For Resource
you can add only the ssm parameters that you want to allow access to, not all of them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With