Using EC2 IAM role principal in SecretsManager resource policy together with autoscaling

0

I got a role named example-role that is attached to an EC2 instance and has full access to SecretsManager. That EC2 got ID i-1234123431.

On the other side, I got a secret that is protected by resource policy that should only grant access to the secret for EC2 instances that do have example-role assigned. I used below resource policy on the secret.

Ultimately I want to use that mechanism as a safety net.

Question 1: I noticed that if I either omit #1 or #2, it is not going to work, i need both. Why I need both?

Question 2: since i need to use #2, how could this work with an autoscaling group where IDs are constantly changing? I tried to use * but looks it is not supported by NotPrincipal. How can I resolve this?

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "secretsmanager:GetSecretValue",
      "NotPrincipal": {
          "AWS": [
              "arn:aws:iam::123456789:root",
              "arn:aws:iam::123456789:role/example-role", #1
              "arn:aws:sts::123456789:assumed-role/example-role/i-1234123431" #2
              ]
      },
      "Resource": "*"
    }
  ]
}
  • Are you trying to implement access to a secret in ONE account from an EC2 instance in ANOTHER account?

AWS
Marco
asked 2 years ago925 views
4 Answers
1

I have to point out there is nothing wrong with your original policy.

The reason why you need both 1 and 2 is that if you are missing either, the effect of the policy might be to explicitly deny access to either the role or the assumed user role.

You can find more details in the NotPrincipal documentation.

Jason_S
answered 2 years ago
  • ah, that makes sense. it was working but the fact #2 does not accept wildcard makes it not really useful as arn of EC2 will change over time. It was given in the doc that NotPrincipal is not accepting wildcards. That is why I was looking for another solution.

0
Accepted Answer

Take a look at the aws:PrincipalArn or aws:userId condition keys.

Your policy with PrincipalArn would look something like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "secretsmanager:GetSecretValue",
      "Principal": {
          "AWS": "*"
      },
      "Resource": "*",
      "Condition": {
          "ArnNotEquals": {
              "aws:PrincipalArn": "arn:aws:iam::123456789:role/example-role"
          }
      }
    }
  ]
}

With aws:userId, you would have something like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "secretsmanager:GetSecretValue",
      "Principal": {
          "AWS": "*"
      },
      "Resource": "*",
      "Condition": {
          "StringNotLike": {
              "aws:userId": "AROAABCDEFGHIJ:*"         # this would be the role's unique ID
          }
      }
    }
  ]
}

Both of these policies avoid having to specify the assumed role principal. The difference is that aws:PrincipalArn ties the policy to the name of the role and aws:userid ties the policy to the unique identifier of the role. This means that if you were to delete and recreate the role, the PrincipalArn policy would continue to work as desired. The aws:userid policy would stop working if a role was recreated with the same name, but had a different unique ID.

The tradeoff is that if you delete the role and do not recreate it, someone else in the account could create a role with the same name and the aws:PrincipalArn policy would not deny that role.

See this post on aws:userid for more information about getting the unique ID for a role.

AWS
Matt
answered 2 years ago
0

Question 1: I suspect the EC2 is accessing the secret in two different ways. Normally you would only need one but I guess the application on EC2 uses two ways of authenticating.

The first way is direct. The EC2 has a default role associated. This would use #1

If a different default role is associated with the EC2 the application needs to use an API call to STS to assume the role (instead of its default one). Thats where #2 is needed.

Question 2: Instead of a Deny you can change the policy to use Allow instead:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "secretsmanager:GetSecretValue",
      "Principal": {
          "AWS": [
              "arn:aws:iam::123456789:root",
              "arn:aws:iam::123456789:role/example-role",
              "arn:aws:sts::123456789:assumed-role/example-role/*"
              ]
      },
      "Resource": "*"
    }
  ]
}
profile picture
JaccoPK
answered 2 years ago
  • It can't be changed to Allow because we want to have explicit deny on the resource policy level. With this, you can achieve explicit deny for everybody except mentioned roles but to use this Parameter, you still need to Allow it in your policy, so it is not magically assigned by resource policy.

0

thanks, that in deed did the job. I tried with StringNotEquals rather than ArnNotEquals what somehow did nor work out for me...but now I am good :-)

AWS
Marco
answered 2 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions