So, your team, or even possibly your entire organization, has decided to standardize on using infrastructure-as-code to define IAM entities within cloud environments. For example, using Terraform to define users, roles, groups, and their policies, instead of defining these directly via the AWS console. Something like this:

resource "aws_iam_user" "user1" {
...
}

resource "aws_iam_group" "developers" {
...
}

resource "aws_iam_user_group_membership" "user-dev" {
  user = aws_iam_user.user1.name
  groups = [
    aws_iam_group.developers.name
  ]
}

resource "aws_iam_policy" "dev-policy" {
  name        = "dev-policy"
  policy      = ...
}

resource "aws_iam_group_policy_attachment" "attach-dev-policy" {
  group      = aws_iam_group.developers.name
  policy_arn = aws_iam_policy.policy.arn
}

You’ve built a nice process around this, with code being controlled via git and the Terraform changes being applied within a CI/CD pipeline. When an auditor, or your own compliance department, asks you how you manage your IAM you proudly show them your Terraform code.

Then they ask: “How do you make sure that no one granted these users/roles permissions outside of your IaC flow?”

*facepalm*

Somebody, with the right permissions, could log into the AWS console and add additional policies for any entity, and you wouldn’t know. The Terraform plan/apply process wouldn’t catch it, because assigning a policy is an additive step and wouldn’t be caught by Terraform’s refresh process. Specifically, this happens because Terraform is refreshing its information about the IAM entity (user/role/group) and the policies it is familiar with. It is not actually going and looking for all of the policies attached to the IAM entity, and therefore can’t see this change. The guys from driftctl explain this well.

Why is this a problem?

This means you don’t have a way to truly track all of the IAM settings in your account. Even with the best IaC flow in place, you will always have a fear that someone has made a change you’re not aware of. Maybe an admin who needed to grant an engineer permissions in the middle of the night to solve a severity-one issue? Or worse, maybe a hacker who managed to attach a policy to an IAM role they control without your knowledge?

Related Article  Comparing IaC Security Tools

How do I catch this?

There are a couple of tools, as well as processes, you can employ:

Driftctl

This is a fairly new tool whose focus is on identifying any drift from your IaC code. One of the primary examples it’s used for is to identify drift in IAM configurations. You can read more about it here. It will also show drift in other resources, such as IAM policy documents, configurations of security groups, etc.

To summarize it, though, driftctl compares your Terraform states to your cloud environment, and tries to see which resources, settings and attachments were modified directly within the cloud environment, while circumventing your IaC process. For example, driftctl will show you this:

Found unmanaged resources:
  aws_iam_policy_attachment:
    - user-1-arn:aws:iam::aws:policy/AdministratorAccess

Indeni Cloudrail

Indeni Cloudrail will parse your Terraform plan, merge it with your cloud account (in memory only), and then analyze the IAM permissions each entity has. It will specifically look to see if there are any attachments of policies in your live cloud environment that are not covered by attachments in the code (like with aws_iam_group_policy_attachment).

If it finds any such deviations, you will get an alert. For example, if somebody applied the Terraform code shown in the beginning of this post, and later someone else went into the AWS console and attached the AdministratorAccess policy directly to the user, you’ll get this:

-----------------------------------------------
Rule: Ensure IAM entities policies are managed solely in infrastructure-as-code
 - 1 Resources Exposed:
-----------------------------------------------
   - Exposed Resource: [myawsaccount] (Not found in TF)
     Violating Resource: [AdministratorAccess]  (Not found in TF)

     Evidence:
         AdministratorAccess
             | is attached to aws_iam_group.developers
             | aws_iam_group.developers is declared in infrastructure-as-code
             | The attachment of the policy was done outside of the code (for example, directly via the console)

For more details on this, checkout this short video by our very own Charles Kim:

Related Article  Integrating AWS's New Policy Validation with Terraform in CI/CD

Lock down IAM control to IaC via an SCP

AWS has the concept of SCP – which allows you to control behavior at an organization level. In a clever idea proposed by Rajeev Sharma, you can use SCP to ensure only your IaC role (for example, Jenkins server) can make IAM changes:

{
  "sid": "iamstuff",
  "Effect": "Deny",
  "Action": [
    "iam:<read/write actions>"
  ],
  "Resource": [
    "arn:aws:iam::*:role/protectedpath/*",
    "arn:aws:iam::*:user/protectedpath/*",
    "arn:aws:iam::*:policy/protectedpath/*"
  ],
  "Condition": {
    "StingNotLike": {
      "aws:PrincipalArn": [
        "arn:aws:iam::*:role/Iac"
      ]
    }
  }
}

Conclusion

Migrating most, if not all, of your cloud infrastructure into IaC is highly advisable, for various reasons, including having control over IAM. However, we must always remember that IaC on its own can be circumvented, and therefore we need to put controls (tools or policies) in place to ensure it isn’t. Or if it is, at least we’ll know 🙂

Try Cloudrail’s drift detection within CI, signup now and be up and running in minutes.