uswitch/kiam

Support specifying tags passed to AssumeRole

bburky opened this issue · 3 comments

An interesting feature to add is allowing specifying the tags used during AssumeRole. AWS allows parameterizing IAM policies based on the role's tags. If it were possible to provide the namespace as a tag, it would allow writing some extremely generic IAM policies parameterized based on namespace.

"Condition": {
    "StringEquals": {"aws:ResourceTag/namespace": "${aws:PrincipalTag/namespace}"}
}

One option might be an additional annotation like iam.amazonaws.com/tags. But I would want a similar permitted style whitelist to ensure a pod can't request tags I don't want it to have. Maybe allow specifying them at the namespace level?

Disclaimer: I've never actually used these kinds of IAM policies, but it looks like a nice way to write a generic IAM policy that works for multiple namespaces. You could tag your S3 buckets with a namespace tag and kiam could manage access quite easily.

Docs:
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_iam-tags.html

Also, it looks like ${aws:userid} expands to role-id:caller-specified-role-name, where "caller-specified-role-name is specified by the RoleSessionName parameter passed to the AssumeRole request." So it might be already possible to stuff metadata into the session name and parameterize your policy based on ${aws:userid}.

Related: #38, changes made in support of specifying session-name and external-id should help with implementing this.

I don't have a specific use case for this, but I just realized that it might be possible to write a single generic parameterized IAM policy for multiple namespaces. I think that would be an extremely usable workflow with kiam: make a single IAM policy, and then add tags to resources as appropriate. It would allow individual workloads to own their resources without making tons of Roles.

@bburky I like this! I have been thinking of using ABAC to solve some of our segmentation needs and this feature would work nicely.

I also like the idea of an allow list for the namespace which restricts in our case what tags our tenants can request which further locks things down.

Are you thinking of getting a PR together for this? I am happy to assist or jump in there and get it done if needed. The changes should not be overly complicated because as you mention the work around session-name and external-id opened support for something like this with minimal pain.

I'm likely not going to look at implementing this at the moment. I honestly... haven't actually deployed kiam yet. I was discussing IAM policies with a coworker who uses it on another project and thought of this design.

I'm happy to talk through what the UX is though.

  • There are a few weird things like you can have an arbitrary number of key/value tags, how do we fit those into the style of annotations that kaim uses? Maybe create multiple annotations like iam.amazonaws.com/tag/foo: a and iam.amazonaws.com/tag/bar: b to represent this, with those becoming AWS role tags of foo=a and bar=b respectively?
  • Is a whitelist at the namespace level the best design?
    • Is limiting the ability to set tags at the namespace level good enough? What are the use cases for setting tags at the Pod level? (This would be easier to implement probably, and lets you set default tags across an entire namespace.)
    • iam.amazonaws.com/permitted is a regex, but that doesn't really work here. I think practical usage will want to restrict the tag keys to an exact list, but may also want to restrict values too: only allow a tag of namespace=foo, where foo should not be configurable within the namespace.
    • Have you considered something like the templating language that CSI drivers use? https://kubernetes-csi.github.io/docs/secrets-and-credentials-storage-class.html
      • Hardcoded tags are easy, specify iam.amazonaws.com/tag/foo: a at the namespace level
      • Restricting a key is doable: specify iam.amazonaws.com/tag/foo: ${pod.annotations['team.example.com/key']} at the namespace level, then team.example.com/key: a at the pod level.
      • Doesn't have a nice way to do restrict keys or values to a pattern though. You can't say "values matching this pattern are okay".
        • You can force a prefix on a tag though: iam.amazonaws.com/tag/foo: prefix-${pod.annotations['team.example.com/key']}.
      • Doesn't have a nice way to specify an allowed list of keys at the namespace level, that Pods can optionally apply.