Onboarding

6 min read

Prerequisites

  • You must have an AWS account and permissions to configure AWS resources.
  • You must have the Admin role in the Footprint dashboard.
  • You must have a YubiKey that supports the PIV card interface over USB. A YubiKey 5C should suffice. Amazon often has the YubiKey 5C NFC available for fast delivery.

1. Install Vault Disaster Recovery tools

First install the CLI tool used for enrollment and decryption. On a Mac, run the following:

bash
1brew install onefootprint/tap/footprint-dr

For other platforms, you can download releases from here.

2. Create an API key and log in with the CLI

Go to the API Keys page on the Footprint dashboard and use the toggle in the top right corner to select Sandbox or Live mode, depending on which data set you would like to enroll.

Create a new API key with an admin scope.

Run footprint-dr login [--sandbox/--live] and paste the API key at the prompt.

Example Output
1$ footprint-dr login --live
2Enter Footprint Live API key: <hidden>

3. Create a bucket for encrypted data storage

Footprint needs a dedicated customer-owned Amazon S3 bucket to store encrypted data. Create a new S3 bucket similar to the one in the Terraform example below. Ensure you are creating the bucket using the us-east-1 region for optimal performance.

terraform
1resource "aws_s3_bucket" "fp_vault_data" {
2  bucket = "acme-inc-footprint-vault-data"
3
4}
5
6resource "aws_s3_bucket_public_access_block" "fp_vault_data_public_access_block" {
7  bucket = aws_s3_bucket.fp_vault_data.id
8
9  block_public_acls       = true
10  block_public_policy     = true
11  ignore_public_acls      = true
12  restrict_public_buckets = true
13}

We recommend that you create this S3 Bucket in a dedicated AWS account with tight access controls. Keeping access to this bucket to a minimum helps reduce the impact of unintentional leaks of an org private key.

We also recommend that you enable CloudTrail audit logs for data events on this bucket. See the following example Terraform:

terraform
1resource "aws_s3_bucket" "fp_vault_data_cloudtrail" {
2  bucket = "acme-inc-footprint-vault-data-cloudtrail"
3}
4
5resource "aws_s3_bucket_public_access_block" "fp_vault_data_cloudtrail_pab" {
6  bucket = aws_s3_bucket.fp_vault_data_cloudtrail.id
7
8  block_public_acls       = true
9  block_public_policy     = true
10  ignore_public_acls      = true
11  restrict_public_buckets = true
12}
13
14locals {
15  fp_vault_data_cloudtrail_name = "footprint-vault-data-cloudtrail"
16}
17
18data "aws_iam_policy_document" "fp_vault_data_cloudtrail" {
19  statement {
20    sid    = "AWSCloudTrailAclCheck"
21    effect = "Allow"
22
23    principals {
24      type        = "Service"
25      identifiers = ["cloudtrail.amazonaws.com"]
26    }
27
28    actions   = ["s3:GetBucketAcl"]
29    resources = [aws_s3_bucket.fp_vault_data_cloudtrail.arn]
30    condition {
31      test     = "StringEquals"
32      variable = "aws:SourceArn"
33      values   = ["arn:${data.aws_partition.current.partition}:cloudtrail:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:trail/${local.fp_vault_data_cloudtrail_name}"]
34    }
35  }
36
37  statement {
38    sid    = "AWSCloudTrailWrite"
39    effect = "Allow"
40
41    principals {
42      type        = "Service"
43      identifiers = ["cloudtrail.amazonaws.com"]
44    }
45
46    actions   = ["s3:PutObject"]
47    resources = ["${aws_s3_bucket.fp_vault_data_cloudtrail.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"]
48
49    condition {
50      test     = "StringEquals"
51      variable = "s3:x-amz-acl"
52      values   = ["bucket-owner-full-control"]
53    }
54    condition {
55      test     = "StringEquals"
56      variable = "aws:SourceArn"
57      values   = ["arn:${data.aws_partition.current.partition}:cloudtrail:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:trail/${local.fp_vault_data_cloudtrail_name}"]
58    }
59  }
60}
61
62resource "aws_s3_bucket_policy" "fp_vault_data_cloudtrail" {
63  bucket = aws_s3_bucket.fp_vault_data_cloudtrail.id
64  policy = data.aws_iam_policy_document.fp_vault_data_cloudtrail.json
65}
66
67resource "aws_cloudtrail" "fp_vault_data_cloudtrail" {
68  name           = local.fp_vault_data_cloudtrail_name
69  s3_bucket_name = aws_s3_bucket.fp_vault_data_cloudtrail.id
70
71  include_global_service_events = false
72
73  depends_on = [aws_s3_bucket_policy.fp_vault_data_cloudtrail]
74
75  event_selector {
76    read_write_type           = "All"
77    include_management_events = true
78
79    data_resource {
80      type = "AWS::S3::Object"
81
82      values = ["${aws_s3_bucket.fp_vault_data.arn}/"]
83    }
84  }
85}

4. Fetch your external ID

Your external ID will help secure the cross-account IAM access. Run footprint-dr get-external-id [--sandbox/--live] to fetch it.

Example Output
1$ footprint-dr get-external-id --live
242ee4f928973996f8f855aebaebf70cd

5. Create an IAM role for bucket management

Footprint needs read and write access to the bucket to manage the encrypted data. Create a IAM role to delegate access like the one in the Terraform example below, substituting your external ID.

terraform
1locals {
2  external_id = "42ee4f928973996f8f855aebaebf70cd"
3}
4
5resource "aws_iam_role" "fp_vault_data_management" {
6  name = "fp-vault-data-management"
7
8  assume_role_policy = data.aws_iam_policy_document.fp_vault_data_management_assume_role_policy.json
9}
10
11data "aws_iam_policy_document" "fp_vault_data_management_assume_role_policy" {
12  statement {
13    actions = ["sts:AssumeRole"]
14
15    principals {
16      type        = "AWS"
17      identifiers = ["725896863556"]
18    }
19
20    condition {
21      test     = "StringEquals"
22      variable = "sts:ExternalId"
23      values   = [local.external_id]
24    }
25  }
26}
27
28data "aws_iam_policy_document" "fp_vault_data_management_policy" {
29  statement {
30    sid = "AllowPutObject"
31
32    actions = [
33      "s3:PutObject",
34    ]
35
36    resources = [
37      "${aws_s3_bucket.fp_vault_data.arn}/*",
38    ]
39  }
40
41  statement {
42    sid = "AllowListBucket"
43
44    actions = [
45      "s3:ListBucket",
46    ]
47
48    resources = [
49      aws_s3_bucket.fp_vault_data.arn,
50    ]
51  }
52
53  statement {
54    sid = "AllowGetBucketLocation"
55
56    actions = [
57      "s3:GetBucketLocation",
58    ]
59
60    resources = [
61      aws_s3_bucket.fp_vault_data.arn,
62    ]
63  }
64}
65
66resource "aws_iam_policy" "fp_vault_data_management" {
67  name   = "fp-vault-data-management"
68  policy = data.aws_iam_policy_document.fp_vault_data_management_policy.json
69}
70
71resource "aws_iam_role_policy_attachment" "fp_vault_data_management_assume_role" {
72  role       = aws_iam_role.fp_vault_data_management.name
73  policy_arn = aws_iam_policy.fp_vault_data_management.arn
74}

6. Generate your Disaster Recovery org key pair

Org identities (private keys) are stored on one or more YubiKeys. Using hardware security tokens helps virtually eliminate the risk of accidentally leaking a private key, which is a sensitive component of the recovery flow. Depending on your data durability requirements, you may choose to mitigate the risk of lost or damaged hardware by registering redundant YubiKeys.

The age YubiKey plugin helps makes the enrollment process simple. Install age and age-plugin-yubikey on a workstation with a USB port for the YubiKey.

bash
1# On a Mac:
2brew install age age-plugin-yubikey ykman

Plug in the YubiKey. Now, change the management key by running the following command. Press the enter key to use the default management key, and enter the default YubiKey pin of 123456 at the prompt.

bash
1ykman piv access change-management-key -a TDES --protect

Then, run a command like the following to generate an age identity for your org. Adjust the name and mode (sandbox/live) for your own reference. You will be prompted to change your PIN/PUK. Choose a PIN and retain it in your password manager of choice. The PIN will be necessary to use your YubiKey to decrypt your Vault Disaster Recovery backups.

bash
1age-plugin-yubikey \
2  --generate \
3  --name "Footprint Vault DR org age identity: Acme Inc. Live" \
4  --pin-policy once \
5  --touch-policy cached \
6  --slot 1

You may choose a different slot number if slot 1 is already in use, though we advise using dedicated YubiKeys for live-mode Vault Disaster Recovery. We recommend the pin policy of once and the touch policy of cached to improve the experience of the test recovery flow.

You do not need to save any of the output, but make note of the recipient (starting with age1yubikey) which you will paste into the next step. You can retrieve the recipient again by running the following:

bash
1age-plugin-yubikey --list

Repeat the key generation step once for each YubiKey you wish to register for Vault Disaster recovery, collecting a list of your org’s age1yubikey age recipients.

7. Complete enrollment

Run footprint-dr enroll [--sandbox/--live] and follow the prompts.

Example Output
1$ footprint-dr enroll --live
2Enrolling Acme Inc. (Live) in Vault Disaster Recovery.
3
4Enter org public key (age recipient): age1yubikey1qgceu0h4fzsv46jg32gnfz0hf5lnaaqm8wn8skxf33qm0t4v4rz427fh79x
5Add another org public key? [y/n] y
6Enter org public key (age recipient): age1yubikey1q2eggw2hftplqfr27s9h8nwuez39m45ms6qv78m9m6kfhmsyf6gacj2km7u
7Add another org public key? [y/n] n
8
9Enter AWS Account ID: 123456789012
10Enter AWS role name: acme-inc-footprint-disaster-recovery
11Enter S3 bucket name: acme-inc-footprint-encrypted-data
12
13Verifying configuration... OK
14
15Enrollment complete.
16
17Store the following information to locate your encrypted data:
18  S3 Bucket Name:   acme-inc-footprint-disaster-recovery
19  Bucket Namespace: a39evoii5rgqhdz4jansho3tten4z0oz

Unplug the YubiKey, clearly label it, and store it in a physically secure location (e.g. an office safe). You will need to retrieve the YubiKey to decrypt Disaster Recovery data.

Store the printed S3 Bucket Name and Bucket Namespace in your records to ensure you can locate your Disaster Recovery data.