Use the AWS Key Management Service with Debusine
Debusine supports the AWS Key Management Service (KMS) for OpenPGP keys used to sign Debian repository indexes.
To set this up, you must have an IAM user in AWS for use by signing workers, with at least the following permissions:
kms:CreateKeykms:Describe*kms:Get*kms:Put*kms:ScheduleKeyDeletionkms:Signkms:TagResource
If you only intend to use pre-generated keys and will never have Debusine
generate keys in KMS by itself, then signing workers only need the
kms:Sign permission.
You should then create a YAML file with cloud provider account
information, stored in
/etc/debusine/signing/aws-account.yaml on your signing worker(s). This
file must be owned by the debusine-signing user and have mode 0600. For
example:
provider_type: aws
name: debusine-kms
configuration:
region_name: eu-west-2
kms_endpoint_url: https://kms.eu-west-2.amazonaws.com/
credentials:
access_key_id: <access key ID>
secret_access_key: <secret access key>
Debusine currently leaves all keys it generates with the default key policy, allowing the AWS account that the signing worker uses to have full access to all keys it generates. If you need something finer-grained, you may override this manually for individual keys using the AWS console or the AWS CLI; see Best practices for IAM policies.
At the time of writing, AWS charges $1/month for each key pair. Since
Debusine instances can have a large number of archives in ephemeral workspaces each of which has its own signing
key, generating all keys in KMS could become quite expensive. To avoid
this, keys are stored using software encryption by default, and an archive
must have its signing_key_storage field set to aws-kms to generate a
key in KMS.
For simplicity and compatibility, Debusine currently only supports Ed25519 repository keys.
Move an existing Debusine signing key into KMS
Importing keys that were generated outside KMS may be useful for the reasons outlined in the AWS documentation on importing key material.
If the key is already stored in Debusine using software encryption, then you
can use the debusine-signing move_key command to move it into KMS. You
will need at least the following additional IAM permissions:
kms:GetParametersForImportkms:ImportKeyMaterial
For example, on a signing worker:
$ sudo debusine-signing move_key openpgp-repository KEY-FINGERPRINT aws-kms
KMS does not allow exporting private key material, so this operation is
irreversible. The command will prompt you for confirmation, unless you use
the --yes option.
Register an existing key not already managed by Debusine
If the key was not stored in Debusine, then you can still import it manually.
As above, you will need at least the following additional IAM permissions:
kms:GetParametersForImportkms:ImportKeyMaterial
The following Python script may be used to extract the raw key material from
an OpenPGP Ed25519 private key and export it in DER-encoded format so that
it can be imported into KMS. You will need to have the
python3-cryptography, python3-pgpy, and sq packages installed.
#! /usr/bin/python3
import subprocess
import sys
from argparse import ArgumentParser
from pathlib import Path
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ed25519
from pgpy.pgp import PGPKey # type: ignore[import-untyped]
parser = ArgumentParser()
parser.add_argument(
"fingerprint",
help=(
"Export the private key of the OpenPGP certificate with this"
" fingerprint"
),
)
parser.add_argument(
"output_file",
type=Path,
help="Write DER-encoded PKCS#8 output to this file",
)
args = parser.parse_args()
export = subprocess.run(
["sq", "key", "export", "--cert", args.fingerprint],
capture_output=True,
check=True,
)
key, _ = PGPKey.from_blob(export.stdout)
# `sq key export` should export the key without a passphrase.
assert not key.is_protected
private_key = key.__key__.__privkey__()
if not isinstance(private_key, ed25519.Ed25519PrivateKey):
print(
"Debusine currently only handles Ed25519 private keys.",
file=sys.stderr,
)
sys.exit(3)
args.output_file.write_bytes(
private_key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
)
Once you have the raw private key material:
Follow the instructions in Create a KMS key with imported key material to import the key in question. When reaching the corresponding steps of those instructions, you should use the
--origin EXTERNAL --key-spec ECC_NIST_EDWARDS25519 --key-usage SIGN_VERIFYoptions toaws kms create-key, the--wrapping-algorithm RSA_AES_KEY_WRAP_SHA_256 --wrapping-key-spec RSA_4096options toaws kms get-parameters-for-import, and the--expiration-model KEY_MATERIAL_DOES_NOT_EXPIREoption toaws kms import-key-material(since Debusine should control expiry).Register the key with
debusine-signingas follows, whereKEY-IDis the key ID given in the output of theaws kms create-keycommand:$ sudo debusine-signing register_aws_kms_key \ openpgp-repository KEY-ID 'some description of the new key'
Create a debusine:signing-key corresponding to the new key, replacing
KEY-DATAby the data printed by the previous command:$ debusine asset create --workspace WORKSPACE --data - \ debusine:signing-key <<END KEY-DATA END
Set the
signing_keysfield of the archive that should use this key. If the output ofdebusine-signing register_aws_kms_keyincludedfingerprint: KEY-FINGERPRINT, then setsigning_keys: [KEY-FINGERPRINT].
Manually generate a key in KMS
You may generate a key manually in KMS if you need more control than
Debusine gives you. Use aws kms create-key --key-spec
ECC_NIST_EDWARDS25519 --key-usage SIGN_VERIFY together with whatever other
options you need. Then follow the steps in the previous section, starting
from “Register the key with debusine-signing”.