Configuration

In this section, we describe the necessary configuration of HashiCorp Vault such that it can be used as a SCION CPPKI Certificate Authority backend by the Anapaya appliance. We also list deployment considerations that an operator should be aware of.

Vault cluster

The Vault cluster is an integral part of the CA architecture. It should be deployed with support for individual Vault node failure. This can be achieved by deploying multiple Vault instances in a cluster. (see: High Availability Mode)

Vault can be run on top of various different databases that provide the storage layer. However, for simplicity, we suggest that Vault is run using the integrated storage.

Note

A Vault setup with a single Vault instance can also work. However, in general we recommend a redundant setup.

Authentication Setup

The Anapaya appliance (via the CA adapter) needs to authenticate itself with Vault to gain access to the target endpoints. For this, the AppRole authentication method must be enabled, and the appropriate roles need to be provisioned. Each CA adapter should get its own individual identity and role_id, such that access to individual Anapaya appliances can be revoked without affecting the remaining appliances.

Each CA adapter should get the right policy assigned, such that it can access the correct Vault PKI Engine and the Key/Value Engine.

To take advantage of the policies that are listed in Policies, the Vault identity for the CA adapter needs to have the isd_as with the ISD-AS number in its metadata. To do this, execute the following steps:

  1. Create a Vault identity for the CA adapter, one identity per adapter instance.

    The suggested name pattern is of the form ca-adapter_<isd-as>-<instance-id>. The metadata should include the key isd_as with the ISD-AS number as the value and the identity should have the CA Adapter Policy attached to it. Use the /identity/entity endpoint to create the identities.

  2. Create a Vault AppRole for each CA adapter instance.

    The suggested name pattern is ca-adapter_<isd-as>-<instance-id>. Use the /auth/approle/role/:role_name endpoint.

  3. Create a Vault entity alias that links the AppRole and the identity together.

    Create an alias so that once you log in with the AppRole you are automatically assigned the entity. For this, you will need the following information:

    • role ID of the CA adapter. Get this with the /auth/approle/role/:role_name/role-id endpoint. (data.role_id in the response body)

    • identity ID of the CA adapter identity. Get this with the /identity/entity/name/:name endpoint. (data.id in the response body)

    • accessor ID of the AppRole authentication engine. Get this with the /sys/auth endpoint. (.["approle/"].accessor in the response body)

    Then, link the AppRole to the identity by creating an alias using the /identity/entity-alias endpoint. The name is set to the role ID, the canonical_id is set to the identity ID, and the mount_accessor is set to the accessor ID.

  4. Extract the role_id and secret_id of the created AppRole(s) to configure the Anapaya appliance where the instance of the CA adapter should run. To read the secret_id, you can use the /auth/approle/role/:role_name/secret-id endpoint.

Secrets Engine Setup

In this section, we describe the different Vault Secrets Engines that are required for the Vault to act as a CA backend.

PKI Engine

Docs: https://www.vaultproject.io/docs/secrets/pki

The PKI engine is the core of the CA backend. It stores the currently active SCION CPPKI CA certificate and the associated private key, and is used to issue the renewed certificates.

Create one active PKI engine per SCION CA AS that is backed by the Vault backend. Each CA adapter only has access to the PKI engine for their respective ISD-AS. The currently active PKI engine is mounted at /ca/<isd-as>/pki. The CA adapter will use the /ca/<isd-as>/sign-verbatim endpoint to request the certificate issuance based on the CSR that it received from the customer AS. For example, the PKI engine for AS 1-ff00:0:110 is mounted at /ca/1-ff00:0:110/pki and the CA adapter will use the endpoint /ca/1-ff00:0:110/pki/sign-verbatim to request the certificate issuance.

We suggest that each PKI engine is only ever associated with exactly one CA certificate. This allows for a clean history of what SCION CPPKI AS certificates were issued with any given SCION CPPKI CA certificate. To achieve this, we recommend the Rolling CA Provision Strategy.

Key/Value Engine

Docs: https://www.vaultproject.io/docs/secrets/kv/kv-v2

The key/value engine is used to keep the state for our CA adapter. For verification of the request, the CA adapter needs the currently active TRC (and potentially the TRC that is currently in the grace period). Furthermore, the CA adapter needs access to the blocklist that allows operators to manually block certain ASes, and prevent them from renewing their certificate.

Again, mount one instance per SCION CPPKI CA AS at /ca/<isd-as>/kv. For example, the key/value engine for AS 1-ff00:0:110 is mounted at /ca/1-ff00:0:110/kv. When enabling the Vault storage mount at ca/<isd-as>/kv, version 2 must be selected.

Note

We require version 2 of the key/value engine in vault. Follow the vault setup documentation and ensure you are using the right version.

  • /ca/<isd-as>/kv/data/trcs hosts the TRCs for the local ISD.

    The TRCs are keyed by the following pattern ISD<isd>-B<base>-S<serial>. The value must be a PEM encoded TRC. For example, the TRC ISD1-B1-S1 is expected to be located at /ca/<isd-as>/kv/data/trcs/ISD1-B1-S1. Additionally, the latest TRC must be located at /ca/<isd-as>/kv/data/trcs/latest.

    The CA adapter uses the TRCs to verify the signatures on the CSRs that are received from the customer AS. It will first look up the latest TRC. If the latest TRC implies that the predecessor TRC is still in the grace period, it will additionally look up that predecessor TRC at the keyed path.

  • /ca/<isd-as>/kv/data/blocklist hosts the blocklist.

    For each AS that is on the blocklist, an entry in the KV storage is required. The data of the entry can be empty, the presence is enough to block an AS. For example to put 1-ff00:0:111 into the blocklist, it suffices to post on the path ca/<isd-as>/kv/data/blocklist/1-ff00:0:111. To check if 1-ff00:0:111 is on the blocklist, read from the same path. If the status code is 404 the item is not on the blocklist, if the status code is 200, the item is blocked.

    The CA adapter uses this blocklist every time it gets a CSR to decide whether a certificate should be issued, or whether the request should be denied.

Policies

Each role gets its individual policy. Each policy should grant the role the minimal set of capabilities for proper operation.

CA Adapter Policy

The CA adapter should only get access to the endpoints belonging to its own ISD-AS. We can leverage identity.entity.metadata.isd_as to ensure this. The metadata is set as part of the AppRole creation for the CA adapter. The CA adapter should get the following policy associated with its role:

# The sign-verbatim endpoint is required to sign new AS certificates.
path "ca/{{identity.entity.metadata.isd_as}}/pki/sign-verbatim" {
    capabilities = ["create", "update"]
}

# TRCs are required in the CA adapter to verify requests.
path "ca/{{identity.entity.metadata.isd_as}}/kv/data/trcs/+" {
    capabilities = ["read"]
}

# Blocklist is required in the CA adapter to validate requests.
path "ca/{{identity.entity.metadata.isd_as}}/kv/data/blocklist/+" {
    capabilities = ["read"]
}

# The CA adapter needs to login via approle to get a token for the other endpoints.
path "auth/approle/login" {
    capabilities = ["create", "update"]
}

CA Provisioning Policy

The exact policy for the CA provisioning is dependent on its implementation. To support the Rolling CA Provision Strategy, the following should be part of the policy:

# The CA provision task needs to be able to configure the CA certificate.
path "ca/+/+/config/ca" {
    capabilities = ["create", "update"]
}

# The CA provision task needs to be able to create new mounts.
path "sys/mounts/ca/+/+" {
    capabilities = ["create", "update", "delete"]
}

# The CA provision task needs to be able to remount old CAs.
path "sys/remount" {
    capabilities = ["create", "update", "sudo"]
    allowed_parameters = {
        "from" = ["ca/*"]
        "to" = ["ca/*"]
    }
}

# The CA provision task needs to be able to tune the newly create PKI engine
path "sys/mounts/ca/+/+/tune" {
    capabilities = ["create", "update"]
    allowed_parameters = {
        "default_lease_ttl" = []
        "max_lease_ttl" = []
        "force_no_cache" = [false]
        "options" = []
    }
}

Manual intervention

The exact policy for manual intervention depends on the capabilities an operator should have in order to intervene. The following is a suggestion with a potentially useful capability set for an operator.

# Provision, list and read TRCs.
patch "ca/+/kv/data/trcs/+" {
    capabilities = ["read", "create", "update"]
}

# Add, list, and delete entities from the blocklist.
patch "ca/+/kv/data/blocklist/+" {
    capabilities = ["read", "create", "update", "delete"]
}

# Manually sign certificates.
path "ca/+/pki/sign-verbatim" {
    capabilities = ["create", "update"]
}

# Manually provision CA certificate.
path "ca/+/pki/config/ca" {
    capabilities = ["create", "update"]
}

# Manually run garbage collection
path "ca/+/pki/tidy" {
    capabilities = ["create", "update"]
}