cmattoon / aws-ssm

Populates Kubernetes Secrets from AWS Parameter Store
https://hub.docker.com/r/cmattoon/aws-ssm/
Apache License 2.0
166 stars 32 forks source link

Add iam role annotation and the ability to assume the role before reading secret #28

Closed SalmaCodes-zz closed 4 years ago

SalmaCodes-zz commented 5 years ago

Make aws-ssm assume a role, that is passed through a kubernetes_secret annotation before reading the parameter.

This allows access to the secret without giving aws-ssm global access, so still allowing our different components to specify their own finer grained security without the complications of merging into a single policy.

mbarrien commented 4 years ago

I'm going to start championing this PR from another colleague of mine, and write a more detailed description.

What this PR allows is increased security for accessing the parameters, by allowing the option to configure the IAM policies to allow aws-ssm's role to only assume roles, not to directly read the secrets. Instead, the roles it is allowed to assume are the entity that is given permissions to read secrets, and the IAM policies on those assumed roles.

This is especially useful in an environment with multiple different people/groups independently managing their own parameters (some of which may not even be used in Kubernetes) but sharing the same AWS account. They can create a role that only has access to that specific group's secrets, using an IAM policy to only restrict it to the subset of parameters they manage, e.g. (in Terraform syntax):

data "aws_iam_policy_document" "role_policy" {
  statement {
    actions = [
      "ssm:GetParametersByPath",
    ]

    resources = ["arn:aws:ssm:us-east-1:123456789012:parameter/parameter-path"]
  }
}

In contrast, the default way to deploy aws-ssm is allowed to read any and all parameters without restriction, which could be a security risk. In theory you can add restrictions directly on aws-ssm's role policy, but this complicates decentralized administration of that single role, as each group would need to keep adding parameters to the list of params aws-ssm is allowed to directly read. In contrast, with roles you can just create another role without touching the centrally maintained aws-ssm.

Even better, with pure IAM and the ability to set resource tags, you can restrict which roles aws-ssm is allowed to assume. In Terraform syntax, here is an example of the role policy you can attach to the role aws-ssm assumes:

data "aws_iam_policy_document" "policy" {
  statement {
    effect    = "Allow"
    actions   = ["sts:AssumeRole"]
    resources = ["*"]

    condition {
      test     = "StringEquals"
      variable = "aws:ResourceTag/allowAwsSsmRoleAssume"
      values   = ["true"]
    }
  }
}

This requires the roles aws-ssm to assume to have a tag and value "allowAwsSsmRoleAssume = true" applied to it, which prevents aws-ssm from assuming just any role. That role in Terraform syntax would look like:

resource "aws_iam_role" "role" {
  name               = "aws-ssm-application-rolename"
  assume_role_policy = data.aws_iam_policy_document.assume-role.json

  tags = {
    allowAwsSsmRoleAssume = "true"
  }
}

Note that competing project https://github.com/godaddy/kubernetes-external-secrets also allows this concept of providing a roleArn that it must assume. This brings this project to parity with that feature. (While in theory we could switch to that project, the advantage of aws-ssm is that it doesn't require CRDs, which are not supported in Terraform.)

We have been running this in production for 9 months with no problems. Please consider merging, or let us know if there's any documentation that would be helpful.

cmattoon commented 4 years ago

Thanks for the PR! I haven't had a chance to review them for a while, but I'll tag a release with all these changes in a bit.