Extending IAM Policy and AWS APIs Using KMS and Lambda
I believe AWS Lambda is an exciting service, though maybe not for the reasons you’d expect. Rather than breathlessly talking about “serverless” services, I think Lambda has potential as a means of providing simple functions that can act as a sort of infrastructural standard library, or in the case of this post, as a means of providing functionality missing from AWS’s own APIs.
Let’s take elastic IPs (EIPs) as an example. If you have an autoscale group that scales up and down based on CPU, but have a need to assign EIPs to each instance, you either have to run an out of band service that manages all of your EIPs, or you need to provide access to the autoscale group’s IAM role to manage every EIP in your infrastructure. It’s not possible to scope individual EIPs to IAM roles.
A lambda that acts as an out of band service, triggered by SNS autoscale events, is a great option here, of course; however, there’s many other examples of AWS APIs that are also un-scopeable and don’t work with this model (most EC2 apis, most route53 actions, etc.). So, I had an idea I wanted to explore for a hackathon this past week, and the API for elastic IPs was a relatively simple API to target.
Last year, during another hackathon, I explored re-using AWS’s IAM credentials for service to service authentication by using the KMS service. We call this KMS authentication. Since then, we’ve integrated it into Confidant and have split it into a general purpose library. The interesting thing about KMS authentication is that it’s an effective way of extending IAM policy, in a way that can be used within your own service.
Combining the extension of IAM policy and lambdas allows us to “scope the un-scopeable”. Let’s take a look at an IAM policy that’s extended to represent actions and resources in a lambda:
The IAM policy for the lambda itself is much simpler:
Before invoking the lambda, we generate the token and username:
Next, we invoke the lambda with the action, resource, instance-id and the username and token:
The lambda will verify the token, then check to ensure the IAM role specified in the ‘from’ context is attached to the instance-id (as an instance profile). It then checks to ensure the action is valid for the specified resource. For instance, for an associate action, it’ll check to ensure an EIP isn’t already associated with another instance. Last, it’ll do the EIP action.
This is a proof of concept, built as a hackathon project, so it could use some improvements, and some of the implementation and design is bound to change; but, take a look at the code, and if you’re interested help make it better!
Interested in open source work and having a big impact? Lyft is hiring! Drop me a note on Twitter or at ryan.lane@lyft.com.