open-vault/website/content/docs/platform/aws/lambda-extension.mdx
John-Michael Faircloth 5d8897528f
docs: add note on aws snapstart incompatibility (#18344)
* add note on snapstart incompatibility

* update note with link to aws and more details

* fix typo
2022-12-13 15:38:38 -06:00

319 lines
23 KiB
Plaintext

---
layout: docs
page_title: Vault Lambda Extension
description: >-
The Vault Lambda Extension allows a Lambda function to read secrets from a Vault deployment.
---
# Vault Lambda Extension
AWS Lambda lets you run code without provisioning and managing servers.
The [Vault Lambda Extension](https://github.com/hashicorp/vault-lambda-extension) utilizes the AWS Lambda Extensions API to help your Lambda function read secrets from your Vault deployment.
You can use the [quick-start](https://github.com/hashicorp/vault-lambda-extension/tree/main/quick-start) directory which has an end-to-end example if you would like to try out the extension from scratch.
~> **Note**: If you decide to create one from scratch, be aware that this will create real infrastructure with an associated cost as per AWS' pricing.
## Usage
To use the extension, include one of the following ARNs as a layer in your
Lambda function, depending on your desired architecture.
amd64 (x86_64):
```text
arn:aws:lambda:<your-region>:634166935893:layer:vault-lambda-extension:13
```
arm64:
```text
arn:aws:lambda:<your-region>:634166935893:layer:vault-lambda-extension-arm64:1
```
Where region may be any of `af-south-1`, `ap-east-1`, `ap-northeast-1`,
`ap-northeast-2`, `ap-northeast-3`, `ap-south-1`, `ap-southeast-1`,
`ap-southeast-2`, `ca-central-1`, `eu-central-1`, `eu-north-1`, `eu-south-1`,
`eu-west-1`, `eu-west-2`, `eu-west-3`, `me-south-1`, `sa-east-1`, `us-east-1`,
`us-east-2`, `us-west-1`, `us-west-2`.
The extension authenticates with Vault using [AWS IAM auth](/docs/auth/aws),
and all configuration is supplied via environment variables. There are two methods
to read secrets, which can both be used side-by-side:
- **Recommended**: Make unauthenticated requests to the extension's local proxy
server at `http://127.0.0.1:8200`, which will add an authentication header and
proxy to the configured `VAULT_ADDR`. Responses from Vault are returned without
modification.
- Configure environment variables such as `VAULT_SECRET_PATH` for the extension
to read a secret and write it to disk.
### Adding the extension to your existing Lambda and Vault infrastructure
#### Requirements
- ARN of the role your Lambda runs as
- An instance of Vault accessible from AWS Lambda
- An authenticated `vault` client
- A secret in Vault that you want your Lambda to access, and a policy giving read access to it
- Your Lambda function must use one of the [supported runtimes][https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html] for extensions
#### Step 1. Configure Vault
Enable the aws auth method.
```shell-session
$ vault auth enable aws
```
Configure the AWS client to use the default options.
```shell-session
$ vault write -force auth/aws/config/client
```
Create a role prefixed with the AWS environment name.
```shell-session
$ vault write auth/aws/role/vault-lambda-role \
auth_type=iam \
bound_iam_principal_arn="${YOUR_ARN}" \
policies="${YOUR_POLICY}" \
ttl=1h
```
#### Step 2. Option a) Install the extension for Lambda functions packaged in zip archives
If you deploy your Lambda function as a zip file, you can add the extension
to your Lambda layers using the console or [cli](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-using):
```text
arn:aws:lambda:<your-region>:634166935893:layer:vault-lambda-extension:11
```
#### Step 2. Option b) Install the extension for Lambda functions packaged in container images
Alternatively, if you deploy your Lambda function as a container image, simply
place the built binary in the `/opt/extensions` directory of your image.
Fetch the binary from
[releases.hashicorp.com](https://releases.hashicorp.com/vault-lambda-extension/).
The following command requires cURL.
```shell-session
$ curl --silent https://releases.hashicorp.com/vault-lambda-extension/0.5.0/vault-lambda-extension_0.5.0_linux_amd64.zip \
--output vault-lambda-extension.zip
```
Unzip the donwloaded binary.
```shell-session
$ unzip vault-lambda-extension.zip
```
Optionally, you can verify the integrity of the downloaded zip using the release
archive checksum verification instructions
[here](https://www.hashicorp.com/security).
Or to build the binary from source. This requires Golang installed. Run from the root of this repository.
```shell-session
$ GOOS=linux GOARCH=amd64 go build -o vault-lambda-extension main.go
```
#### Step 3. Configure vault-lambda-extension
Configure the extension using [Lambda environment
variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html):
Set the Vault API address.
```shell-session
$ VAULT_ADDR=http://vault.example.com:8200
```
Set the AWS IAM auth mount point (i.e. the path segment after `auth/` from above).
```shell-session
$ VAULT_AUTH_PROVIDER=aws
```
Set the Vault role to authenticate as. Must be configured for the ARN of your
Lambda's role.
```shell-session
$ VAULT_AUTH_ROLE=vault-lambda-role
```
The path to a secret in Vault. Can be static or dynamic. Unless
VAULT_SECRET_FILE is specified, JSON response will be written to
`/tmp/vault/secret.json`.
```shell-session
$ VAULT_SECRET_PATH=secret/lambda-app/token
```
If everything is correctly set up, your Lambda function can then read secret
material from `/tmp/vault/secret.json`. The exact contents of the JSON object
will depend on the secret read, but its schema is the [Secret struct](https://github.com/hashicorp/vault/blob/api/v1.0.4/api/secret.go#L15)
from the Vault API module.
Alternatively, you can send normal Vault API requests over HTTP to the local
proxy at `http://127.0.0.1:8200`, and the extension will add authentication
before forwarding the request. Vault responses will be returned unmodified.
Although local communication is over plain HTTP, the proxy server will use TLS
to communicate with Vault if configured to do so as detailed below.
## Configuration
The extension is configured via [Lambda environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html).
Most of the [Vault CLI client's environment variables](/docs/commands#environment-variables) are available,
as well as some additional variables to configure auth, which secret(s) to read and
where to write secrets.
| Environment variable | Description | Required | Example value |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------- |
| `VLE_VAULT_ADDR` | Vault address to connect to. Takes precedence over `VAULT_ADDR` so that clients of the proxy server can be configured using the standard `VAULT_ADDR` | No | `https://x.x.x.x:8200` |
| `VAULT_ADDR` | Vault address to connect to if `VLE_VAULT_ADDR` is not set. Required if `VLE_VAULT_ADDR` is not set | No | `https://x.x.x.x:8200` |
| `VAULT_AUTH_PROVIDER` | Name of the configured AWS IAM auth route on Vault | Yes | `aws` |
| `VAULT_AUTH_ROLE` | Vault role to authenticate as | Yes | `lambda-app` |
| `VAULT_IAM_SERVER_ID` | Value to pass to the Vault server via the [`X-Vault-AWS-IAM-Server-ID` HTTP Header for AWS Authentication](/api-docs/auth/aws#iam_server_id_header_value) | No | `vault.example.com` |
| `VAULT_SECRET_PATH` | Secret path to read, written to `/tmp/vault/secret.json` unless `VAULT_SECRET_FILE` is specified | No | `database/creds/lambda-app` |
| `VAULT_SECRET_FILE` | Path to write the JSON response for `VAULT_SECRET_PATH` | No | `/tmp/db.json` |
| `VAULT_SECRET_PATH_FOO` | Additional secret path to read, where FOO can be any name, as long as a matching `VAULT_SECRET_FILE_FOO` is specified | No | `secret/lambda-app/token` |
| `VAULT_SECRET_FILE_FOO` | Must exist for any correspondingly named `VAULT_SECRET_PATH_FOO`. Name has no further effect beyond matching to the correct path variable | No | `/tmp/token` |
| `VAULT_TOKEN_EXPIRY_GRACE_PERIOD` | Period at the end of the proxy server's auth token TTL where it will consider the token expired and attempt to re-authenticate to Vault. Must have a unit and be parseable by `time.Duration`. Defaults to 10s. | No | `1m` |
| `VAULT_STS_ENDPOINT_REGION` | The region of the STS regional endpoint to authenticate with. If the AWS IAM auth mount specified uses a regional STS endpoint, then this needs to match the region of that endpoint. Defaults to using the global endpoint, or the region the Lambda resides in if `AWS_STS_REGIONAL_ENDPOINTS` is set to `regional` | No | `eu-west-1` |
The remaining environment variables are not required, and function exactly as
described in the [Vault Commands (CLI)](/docs/commands#environment-variables) documentation. However,
note that `VAULT_CLIENT_TIMEOUT` cannot extend the timeout beyond the 10s
initialization timeout imposed by the Extensions API when writing files to disk.
| Environment variable | Description | Required | Example value |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------- |
| `VAULT_CACERT` | Path to a PEM-encoded CA certificate _file_ on the local disk | No | `/tmp/ca.crt` |
| `VAULT_CAPATH` | Path to a _directory_ of PEM-encoded CA certificate files on the local disk | No | `/tmp/certs` |
| `VAULT_CLIENT_CERT` | Path to a PEM-encoded client certificate on the local disk | No | `/tmp/client.crt` |
| `VAULT_CLIENT_KEY` | Path to an unencrypted, PEM-encoded private key on disk which corresponds to the matching client certificate | No | `/tmp/client.key` |
| `VAULT_CLIENT_TIMEOUT` | Timeout for Vault requests. Default value is 60s. Ignored by proxy server. **Any value over 10s will exceed the Extensions API timeout and therefore have no effect** | No | `5s` |
| `VAULT_MAX_RETRIES` | Maximum number of retries on `5xx` error codes. Defaults to 2. Ignored by proxy server | No | `2` |
| `VAULT_SKIP_VERIFY` | Do not verify Vault's presented certificate before communicating with it. Setting this variable is not recommended and voids Vault's [security model](/docs/internals/security) | No | `true` |
| `VAULT_TLS_SERVER_NAME` | Name to use as the SNI host when connecting via TLS | No | `vault.example.com` |
| `VAULT_RATE_LIMIT` | Only applies to a single invocation of the extension. See [Vault Commands (CLI)](/docs/commands#environment-variables) documentation for details. Ignored by proxy server | No | `10` |
| `VAULT_NAMESPACE` | The namespace to use for pre-configured secrets. Ignored by proxy server | No | `education` |
| `VAULT_DEFAULT_CACHE_TTL` | The time to live configuration (aka, TTL) of the cache used by proxy server. Must have a unit and be parsable as a time.Duration. Required for caching to be enabled. | No | `15m` |
| `VAULT_DEFAULT_CACHE_ENABLED` | Enable caching for all requests, without needing to set the X-Vault-Cache-Control header for each request. Must be set to a boolean value. | No | `true` |
| `VAULT_ASSUMED_ROLE_ARN` | Valid ARN of an IAM role that can be assumed by the execution role assigned to your Lambda function. | No | `arn:aws:iam::123456789012:role/xaccounts3access`
| `VAULT_LOG_LEVEL` | Log verbosity level, one of TRACE, DEBUG, INFO, WARN, ERROR, OFF. Defaults to INFO. | No | `DEBUG`
### AWS STS client configuration
In addition to Vault configuration, you can configure certain aspects of the STS
client the extension uses through the usual AWS environment variables. For example,
if your Vault instance's IAM auth is configured to use regional STS endpoints:
```shell-session
$ vault write auth/aws/config/client \
sts_endpoint="https://sts.eu-west-1.amazonaws.com" \
sts_region="eu-west-1"
```
Then you may need to configure the extension's STS client to also use the regional
STS endpoint by setting `AWS_STS_REGIONAL_ENDPOINTS=regional`, because both the AWS Golang
SDK and Vault IAM auth method default to using the global endpoint in many regions.
See documentation on [`sts_regional_endpoints`](https://docs.aws.amazon.com/credref/latest/refdocs/setting-global-sts_regional_endpoints.html) for more information.
### Caching
Caching can be configured for the extension's local proxy server so that it does
not forward every HTTP request to Vault. The main consideration behind caching
design is to make caching an explicit opt-in at the request level, so that it is
only enabled for scenarios where caching makes sense without negative impact in
others. To turn on caching, set the environment variable
`VAULT_DEFAULT_CACHE_TTL` to a valid value that is parsable as a time.Duration
in Go, for example, "15m", "1h", "2m3s" or "1h2m3s", depending on application
needs. An invalid or negative value will be treated the same as a missing value,
in which case, caching will not be set up and enabled.
Then requests with HTTP method of "GET", and the HTTP header
`X-Vault-Cache-Control: cache` will be returned directly from the cache if
there's a cache hit. On a cache miss the request will be forwarded to Vault and
the response returned and cached. If the header is set to
`X-Vault-Cache-Control: recache`, the cache lookup will be skipped, and the
request will be forwarded to Vault and the response returned and cached.
Currently, the cache key is a hash of the request URL path, headers, body, and
token.
Caching may also be enabled for all requests by setting the environment variable
`VAULT_DEFAULT_CACHE_ENABLED` to `true`. Then all requests will be fetched and/or
cached as though the header `X-Vault-Cache-Control: cache` was present. Setting
the header to `nocache` on a request will opt-out of caching entirely in this
configuration. Setting the header to `recache` will skip the cache lookup and
return and cache the response from Vault as described previously.
## Limitations
Secrets written to disk or returned from the proxy server will not be automatically
refreshed when they expire. This is particularly important if you configure the
extension to write secrets to disk, because the extension will only write to disk
once per execution environment, rather than once per function invocation. If you
use [provisioned concurrency](https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html#configuration-concurrency-provisioned) or if your Lambda
is invoked often enough that execution contexts live beyond the lifetime of the
secret, then secrets on disk are likely to become invalid.
In line with [Lambda best practices](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html), we recommend avoiding
writing secrets to disk where possible, and exclusively consuming secrets via
the proxy server. However, the proxy server will still not perform any additional
processing with returned secrets such as automatic lease renewal. The proxy server's
own Vault auth token is the only thing that gets automatically refreshed. It will
synchronously refresh its own token before proxying requests if the token is
expired (including a grace window), and it will attempt to renew its token if the
token is nearly expired but renewable.
~> **Note**: The Vault Lambda Extension is currently incompatible with
[AWS SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html).
This is because AWS SnapStart does not support the Lambda Extensions API.
## Performance impact
AWS Lambda pricing is based on [number of invocations, time of execution and memory
used](https://aws.amazon.com/lambda/pricing/). The following table details some approximate performance
related statistics to help assess the cost impact of this extension. Note that AWS
Lambda allocates [CPU power in proportion to memory](https://docs.aws.amazon.com/lambda/latest/dg/configuration-memory.html) so results
will vary widely. These benchmarks were run with the minimum 128MB of memory allocated
so aim to give an approximate baseline.
| Metric | Value | Description | Derivation |
| -------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Layer size | 8.5MB | The size of the unpacked extension binary | `ls -la` |
| Init latency | 8.5ms (standard deviation 2.4ms) + one network round trip to authenticate to Vault | Extension initialization time in a new execution environment. Authentication round trip time will be highly deployment-dependent | Instrumented in code |
| Invoke latency | <1ms | The base processing time for each function invocation, assuming no calls to the proxy server | Instrumented in code |
| Memory impact | 12MB | The marginal impact on "Max Memory Used" when running the extension | As reported by Lambda when running Hello World function with and without extension |
## Uploading to your own AWS account and region
If you would like to upload the extension as a Lambda layer in your own AWS
account and region, you can do the following:
```shell-session
$ curl --silent https://releases.hashicorp.com/vault-lambda-extension/0.5.0/vault-lambda-extension_0.5.0_linux_amd64.zip \
--output vault-lambda-extension.zip
```
Set your target AWS region.
```shell-session
$ export REGION="YOUR REGION HERE"
```
Upload the extension as a Lambda layer.
```shell-session
$ aws lambda publish-layer-version \
--layer-name vault-lambda-extension \
--zip-file "fileb://vault-lambda-extension.zip" \
--region "${REGION}"
```
## Tutorial
For step-by-step instructions, refer to the [Vault AWS Lambda Extension](https://learn.hashicorp.com/tutorials/vault/aws-lambda) tutorial for details on how to create an AWS Lambda function and use the Vault Lambda Extension to authenticate with Vault.