⚠️ Biscuit is no longer maintained. Do not use Biscuit on new projects.
Biscuit is a simple key-value store for your infrastructure secrets.
Biscuit is most useful to teams already using AWS and IAM to manage their infrastructure. If that describes your team, then Biscuit might be useful to you if you answer "yes" to any of these questions:
- Do you live in constant fear of accidentally committing infrastructure secrets to source control?
- Do you commit private keys to your source repository?
- Do you share passwords with other developers?
- Do you want to manage secrets securely across multiple regions?
- Provides a simple key/value CLI to secure storage.
- Secrets can live alongside with your code in source control.
- Operates with KMS keys across multiple regions.
- Facilitates management of AWS IAM Policies, KMS Policies, and KMS Grants across multiple regions.
- Local encryption using AES-GCM-256 or Secretbox (NaCL).
- Offline mode: Using the "testing" key manager, you can use Biscuit in test environments without changing your code and without network dependencies.
Package | Requires a server? | Multi-region | HA | Rotation | Storage | AWS KMS | Principals | Web UI |
---|---|---|---|---|---|---|---|---|
Biscuit | No | Yes | Yes | No | File | Required | AWS Only | No |
Credstash | No | No | Yes | No | DynamoDB | Required | AWS Only | No |
Lyft Confidant | Yes | No | No | No | DynamoDB | Required | AWS Only | Yes |
Hashicorp Vault | Yes | Yes | Yes | Yes | Varied | Optional | Multiple | No |
See releases for the latest release.
If you have Golang 1.16+ installed, you can install with:
go get -v github.com/dcoker/biscuit
# Verify that your AWS credentials are readable.
biscuit kms get-caller-identity
# Provision a KMS Key w/useful defaults in us-east-1, us-west-1,
# and us-west-2 and create a secrets.yml file.
biscuit kms init -f secrets.yml
# Store the launch codes.
biscuit put -f secrets.yml -- launch_codes 0000
# Decrypt the launch codes.
biscuit get -f secrets.yml launch_codes
Next steps: examine secrets.yml
in your favorite text editor, and run
biscuit --help
to learn about additional commands.
Done already?
The biscuit kms init
step above may have created a KMS Key and some
associated policies using CloudFormation. You can remove those by
running:
biscuit kms deprovision
rm secrets.yml
Note: any biscuit files you created before deprovisioning will no longer be readable.
The secret is the plaintext value which you wish to protect.
A label is a short alphanumeric string that identifies a set of keys
across multiple AWS regions. It is present in CloudFormation stack names
(biscuit-label
) and in KMS key aliases (alias/biscuit-label
).
The key manager is responsible for the provisioning of encryption keys. The encryption keys generated by the key manager are used to encrypt the secret. An encrypted version of the encryption key -- decryptable only by KMS -- is stored as the key ciphertext.
Secret values consist of the information necessary for the key
manager to provide the plaintext encryption key to decrypt a
ciphertext for a named secret. Values consist of a Key ID (a
string, meaningful to the key manager), an indicator of which key manager is
in use (string), an algorithm (string), the key ciphertext (the
encrypted key, base64), and the ciphertext (base 64). Here is an example
of a value named api_key
:
api_key:
- key_id: arn:aws:kms:us-west-1:123456789012:key/37793df5-ad32-4d06-b19f-bfb95cee4a35
key_manager: kms
algorithm: secretbox
key_ciphertext: CiA3edlKfUWXVgiDDuzbz95S/pkM8grwRsYkjRoURv0LGhKnAQEBAQB4N3nZSn1Fl1YIgw7s28/eUv6ZDPIK8EbGJI0aFEb9CxoAAAB+MHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAw4OEtFZrisfC3xJHACARCAO+HJpH4bWD/MF9BYjBvl5ztcezTNxo5SPeAOKJ3Z8Pff2vh1uCZhEEjxnF7t1tqTma8oeESuu2vpPiZp
ciphertext: YsI/4Qnzpu+Vm+JP4LhnO8Y3dSoz61/vKHBXGVI1pVAUCjMhvjb9ohcdjA==
Names identify a value. When using AWS KMS, names are encoded into the encryption context and must be provided by the process that decrypts the value.
A key template is a special entry in the .yml file which tells the biscuit tool how to handle values that are added to that file. This is an example template:
_keys:
- key_id: arn:aws:kms:us-west-1:123456789012:key/37793df5-ad32-4d06-b19f-bfb95cee4a35
key_manager: kms
algorithm: secretbox
- key_id: arn:aws:kms:us-west-2:123456789012:key/c0045b15-9880-4b17-84da-a35760e8a16f
key_manager: kms
algorithm: secretbox
- key_id: arn:aws:kms:us-east-1:123456789012:key/d1c5a8e3-adfb-4f79-af0b-cde9f1a31292
key_manager: kms
algorithm: secretbox
Biscuit requires one key in each region you wish to use. Most users can expect to pay ~$1/mo per region per label, and additional usage charges for heavy users. See AWS Key Management Service Pricing for pricing.
Yes. Use the -r
flag or the BISCUIT_REGIONS
environment variable to specify
the region.
Example:
biscuit kms init -r us-west-2 -f secrets.yml
The .yml file is safe for committing to version control, your CI system, embedding in native binaries, copying to S3, publishing in a newspaper, etc. You can deploy these to your production servers by whatever mechanism is most appropriate for your environment, but by far the easiest way to start is to simply include it in your deployments in the same way you would a configuration file.
You can use KMS Grants, KMS Key Policies, or IAM Policies to manage access to the secrets.
KMS Grants enable you to delegate access to specific KMS operations to some AWS principal. Often your AWS resources will be running with an IAM Role, and thus often the easiest thing to do is to use KMS Grants to allow your IAM Roles to decrypt the appropriate values.
Biscuit will create and retire those grants for you.
Here's how to grant role/webserver and user/gordon the ability to decrypt the launch codes:
biscuit kms grants create --grantee-principal role/webserver -f secrets.yml launch_codes
biscuit kms grants create --grantee-principal user/gordon -f secrets.yml launch_codes
biscuit kms grants list -f secrets.yml launch_codes
If you wish to allow a principal to decrypt all values encrypted under the same set of keys as
the launch codes, you can pass the --all-names
flag:
biscuit kms grants create -g role/webserver -f secrets.yml --all-names launch_codes
You can also retire grants when they are no longer useful:
biscuit kms grants list -f secrets.yml launch_codes
biscuit kms grants retire -f secrets.yml --grant-name biscuit-ff8102edc8 launch_codes
Biscuit manages grants using the KMS CreateGrant, ListGrants, and RetireGrant APIs.
KMS Keys have their own policies. See
Key Policies
for more details. If you have just a few users, this is possibly the easiest
mechanism to use to control access. You can run biscuit kms edit-key-policy
to
edit the policy document across all of your regions at once.
Biscuit manages Key Policies using the KMS GetKeyPolicy and SetKeyPolicy APIs.
IAM Policies are attached to a myriad of AWS entities, and they can also be used to enable access to KMS operations. See Key Policies for more details.
Example: You have a server running with a static AWS access key and secret key. You can give that
server the ability to decrypt all values encrypted under a set of keys by attaching a standard user policy,
specifying kms:Decrypt
as the Action and the full key ARNs in the Resource field.
Note: IAM Policies are global entities, whereas KMS Keys are unique per region. Thus if you have a 3-region configuration, any IAM Policies that explicitly grant access to KMS Keys will need to list all 3 region-specific key ARNs.
Biscuit does not manage IAM Policies for you.
If you wish to disallow IAM Policies from controlling access to your keys,
you can do so by passing --disable-iam-policies
to kms init
. When IAM
Policies are disabled, the only way to control access to keys is via Grants and KMS Key
Policies. For more information on how this works, see the CloudFormation
template in the source repository and the Key Policies doc linked above.
Each AWS region has its own isolated KMS instance. This means that KMS keys are per-region resources, and using a KMS key requires communicating with the KMS service in the region that holds that key.
When encrypting, Biscuit will attempt to encrypt the secrets by using all of the KMS instances corresponding to the regions of the keys it is told to use. This can incur cross-datacenter traffic and is slower than using only the closest region.
When decrypting, Biscuit only needs to decrypt under one of the keys. By
default, Biscuit will prioritize using keys that are in the same region that
the caller is in. This is determined by the AWS_REGION
environment variable.
If you do not have an AWS_REGION
variable set, Biscuit will process keys in
the order that they appear in the .yaml file.
You can override this behavior by passing a --aws-region-priority
flag to the
get
or export
operations. Here is an example invocation which prioritizes
keys in ap-north-1 and us-west-2:
biscuit get --aws-region-priority ap-north-1,us-west-2 -f secrets.yml launch_codes
We recommend you make arrangements on your EC2 instances to either set the
AWS_REGION
flag, or pass a latency-ordered list of regions via the
--aws-region-priority
flag.
Biscuit tracks keys across regions by using a label. Labels are embedded
into the name of the CloudFormation stack and a KMS Key Alias in each region.
The default behavior is to use the default
label, but you can change this
by passing the -l
flag. Example: biscuit kms init -l development
Labels are not persisted with the values and are not visible in the .yml files. They are an organizational tool to facilitate managing keys across regions, and are passed as parameters to various commands.
Here are some common scenarios:
# Create key in a single-region, and allow developers to do whatever they want.
biscuit kms init -r us-west-2 -l development -f development.yml --administrators role/developers --users role/developers
biscuit put -f development.yml ssl_key -i selfsigned.key
# Create keys in three regions, and allow a limited set of people to administer it,
# and allow developers (and gordon) to read and write the secrets.
biscuit kms init -l production -f production.yml --administrators role/prod-keymaster --users role/developers,user/gordon
biscuit put -f production.yml ssl_key -i wildcard.key
# Create a file that doesn't use encryption at all.
biscuit put -f unittest.yml -a none -- database_password testing
Biscuit installs a KMS Key Policy similar to the default policy recommended by AWS. This creates a distinction between "administrators" and "users".
Administrators can administer the key but not necessarily encrypt or decrypt with that key. They could, if they wished, replace the key policy with one that does allow them encrypt and decrypt, but that would be unusual.
Users can encrypt, decrypt, and generate ephemeral data keys. In most cases, you'll want to make your development team a "user" and possibly also "administrators".
If you use biscuit kms init
to create your keys, you can use the
--administrators
and --users
flag to set membership. If you have already
created the keys but want to change the policy, use the interactive
biscuit kms edit-key-policy
to apply changes to all regions simultaneously.
The IAM Policy below is the smallest set of permissions needed to get
started with Biscuit using kms init
. Be sure to replace the account
number 123456789012
with your own.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowKmsListAliasesAndCreateKey",
"Effect": "Allow",
"Action": [
"kms:ListAliases",
"kms:CreateKey"
],
"Resource": [
"*"
]
},
{
"Sid": "AllowKmsCreateAlias",
"Effect": "Allow",
"Action": [
"kms:CreateAlias"
],
"Resource": [
"arn:aws:kms:*:123456789012:alias/biscuit-*"
]
},
{
"Sid": "AllowKmsDeleteAlias",
"Effect": "Allow",
"Action": [
"kms:DeleteAlias"
],
"Resource": [
"arn:aws:kms:*:123456789012:alias/biscuit-*"
]
},
{
"Sid": "AllowCloudFormationCreate",
"Effect": "Allow",
"Action": [
"cloudformation:DescribeStacks",
"cloudformation:CreateStack",
"cloudformation:DeleteStack"
],
"Resource": [
"arn:aws:cloudformation:*:123456789012:stack/biscuit-*"
]
},
{
"Sid": "AllowCloudFormationDelete",
"Effect": "Allow",
"Action": [
"cloudformation:DeleteStack"
],
"Resource": [
"arn:aws:cloudformation:*:123456789012:stack/biscuit-*"
]
}
]
}
Yes. IAM Policies and the KMS Key Policies support the aws:MultiFactorAuthPresent
condition.
Biscuit does not enforce any access control on its own. All enforcement is implemented by AWS. Any features that are available in the IAM Policies, KMS Key Policy documents, or KMS Grants are available to you.
Biscuit does not expose command line flags to use all of the features, but you can edit the various policies after they are created, or override the default CloudFormation template.
Biscuit is known to work well with awsmfa.
I manually edited the .yaml file and changed the name of a value and now it won't decrypt. What's wrong?
The kms
key manager annotates the ciphertext with an
EncryptionContext
containing the name of the value. If you change the name of a value,
then the decrypting process will provide the wrong name to the decrypt
operation and the decrypt will fail. If you wish to change the name of a
secret, re-encrypt it using the new name instead.
The biscuit kms init
command allows you to override the built-in
CloudFormation template with your own via the
--cloudformation-template-url
parameter.
The only expectations that Biscuit has about your KMS configuration is that the
keys have aliases of the form alias/biscuit-{label}
and that you have sufficient
permissions to operate on the KMS keys. You can create the keys using whatever
process is compatible with your organization's policies.
Biscuit considers the rotation of secrets (such as database passwords) to be application-specific features and thus does not have any native support for it. However, you can implement a rotation scheme appropriate for your situation simply by serializing that state as the secret and then read it with your application-specific rotation behaviors.
Here is an example using JSON and jq:
biscuit put -f secrets.yml -- database_passwords '{"1": "pass1", "2": "pass2"}'
biscuit get -f secrets.yml database_passwords | jq -r '.[to_entries | map(.key) | map(tonumber) | max | tostring]'