Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nebula_ca plugin #539

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ reqwest = { version = "0.12", default-features = false, features = [
rstest = "0.18.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.132"
serde_qs = "0.13.0"
serde_with = { version = "1.11.0", features = ["base64", "hex"] }
serial_test = { version = "3.2.0", features = ["async"] }
sha2 = "0.10"
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:
- "8080:8080"
volumes:
- ./kbs/data/kbs-storage:/opt/confidential-containers/kbs/repository:rw
- ./kbs/data/nebula-ca:/opt/confidential-containers/kbs/nebula-ca:rw
- ./kbs/config/public.pub:/opt/confidential-containers/kbs/user-keys/public.pub
- ./kbs/config/docker-compose/kbs-config.toml:/etc/kbs-config.toml
depends_on:
Expand Down
7 changes: 6 additions & 1 deletion kbs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ aliyun = ["kms/aliyun"]
# Use pkcs11 resource backend to store secrets in an HSM
pkcs11 = ["cryptoki"]

# Use Nebula Certificate Authority plugin to provide CA services to nodes
# that want to join a Nebula overlay network
nebula-ca-plugin = []

[dependencies]
actix = "0.13.5"
actix-web = { workspace = true, features = ["openssl"] }
Expand Down Expand Up @@ -60,10 +64,12 @@ regorus.workspace = true
reqwest = { workspace = true, features = ["json"] }
rsa = { version = "0.9.2", features = ["sha2"] }
scc = "2"
serde_qs.workspace = true
semver = "1.0.16"
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
strum.workspace = true
tempfile.workspace = true
thiserror.workspace = true
time = { version = "0.3.23", features = ["std"] }
tokio.workspace = true
Expand All @@ -90,7 +96,6 @@ attestation-service = { path = "../attestation-service", default-features = fals


[dev-dependencies]
tempfile.workspace = true
rstest.workspace = true
reference-value-provider-service.path = "../rvps"

Expand Down
5 changes: 5 additions & 0 deletions kbs/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
AS_TYPE ?= coco-as
ALIYUN ?= false
NEBULA_CA_PLUGIN ?= false

BUILD_ARCH := $(shell uname -m)
ARCH ?= $(shell uname -m)
Expand Down Expand Up @@ -48,6 +49,10 @@ ifeq ($(ALIYUN), true)
FEATURES += aliyun
endif

ifeq ($(NEBULA_CA_PLUGIN), true)
FEATURES += nebula-ca-plugin
endif

ifndef CLI_FEATURES
ifdef ATTESTER
CLI_FEATURES = "sample_only,$(ATTESTER)"
Expand Down
11 changes: 10 additions & 1 deletion kbs/docker/coco-as-grpc/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ FROM --platform=$BUILDPLATFORM rust:latest AS builder
ARG BUILDPLATFORM=linux/amd64
ARG ARCH=x86_64
ARG ALIYUN=false
ARG NEBULA_CA_PLUGIN=false
ARG NEBULA_VERSION=v1.9.5

WORKDIR /usr/src/kbs
COPY . .
Expand All @@ -17,11 +19,18 @@ RUN if [ $(uname -m) != ${ARCH} ]; then \
apt-get install -y libssl-dev:${OS_ARCH}; fi

# Build and Install KBS
RUN cd kbs && make AS_FEATURE=coco-as-grpc ALIYUN=${ALIYUN} ARCH=${ARCH} && \
RUN cd kbs && make AS_FEATURE=coco-as-grpc ALIYUN=${ALIYUN} ARCH=${ARCH} NEBULA_CA_PLUGIN=${NEBULA_CA_PLUGIN} && \
make ARCH=${ARCH} install-kbs

# Download and install Nebula
RUN if [ "${NEBULA_CA_PLUGIN}" = "true" ]; then \
curl -fSLO https://github.com/slackhq/nebula/releases/download/${NEBULA_VERSION}/nebula-$(echo ${BUILDPLATFORM} | sed 's/\//-/').tar.gz && \
tar -C /usr/local/bin -xzf nebula-$(echo "${BUILDPLATFORM}" | sed 's/\//-/').tar.gz; \
fi

FROM ubuntu:22.04

LABEL org.opencontainers.image.source="https://github.com/confidential-containers/trustee/kbs"

COPY --from=builder /usr/local/bin/kbs /usr/local/bin/kbs
COPY --from=builder /usr/local/bin/nebula-cert* /usr/local/bin/nebula-cert
47 changes: 47 additions & 0 deletions kbs/docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,39 @@ This is also called "Repository" in old versions. The properties to be configure
| `password` | String | AAP client key password | Yes | `8f9989c18d27...` |
| `cert_pem` | String | CA cert for the KMS instance | Yes | `-----BEGIN CERTIFICATE----- ...` |

#### Nebula CA Configuration

The `name` field is `nebula-ca` to enable this plugin.

The table below describes the properties supported to configure the plugin, they are all optional.

| Property | Type | Description | Default |
|------------------------|--------|-----------------------------------|----------|
| `nebula_cert_bin_path` | String | `nebula-cert` binary path | If not provided, `nebula-cert` will be searched in $PATH |
| `work_dir` | String | This plugin work directory, it requires `rw` permission | `/opt/confidential-containers/kbs/nebula-ca` |
| `[plugins.self_signed_ca]` | SubSection | Nebula CA credential properties | See table below |

The properties supported under `[plugins.self_signed_ca]` are described in the table below. They are all optional.

When the KBS is starting, the plugin will try to load the CA credential from `${work_dir}/ca/ca.{key,crt}`, otherwise, it will create a new self-signed CA credential based on the `[plugins.self_signed_ca]` properties provided. The default value will be considered if a `[plugins.self_signed_ca]` property is not provided.

| Property | Type | Description | Default | Example |
|---------------------|---------|-----------------------------------|----------|-----------------------------------------------------|
| `name` | String | Name of the certificate authority | `Trustee Nebula CA plugin` | |
| `argon_iterations` | Integer | Argon2 iterations parameter used for encrypted private key passphrase | 1 | |
| `argon_memory` | Integer | Argon2 memory parameter (in KiB) used for encrypted private key passphrase | 2097152 | |
| `argon_parallelism` | Integer | Argon2 parallelism parameter used for encrypted private key passphrase | 4 | |
| `curve` | String | EdDSA/ECDSA Curve (25519, P256) | `25519` | |
| `duration` | String | Amount of time the certificate should be valid for. Valid time units are: <hours>"h"<minutes>"m"<seconds>"s" | `8760h0m0s` | |
| `groups` | String | Comma separated list of groups. This will limit which groups subordinate certs can use | "" | `server,ssh` |
| `ips` | String | Comma separated list of ipv4 address and network in CIDR notation. This will limit which ipv4 addresses and networks subordinate certs can use for ip addresses | "" | `192.168.100.10/24,192.168.100.15/24` |
| `out_qr` | String | Path to write a QR code image (png) of the certificate | | `/opt/confidential-containers/kbs/nebula_ca/ca_qr.crt`|
| `subnets` | String | Comma separated list of ipv4 address and network in CIDR notation. This will limit which ipv4 addresses and networks subordinate certs can use in subnets | "" | `192.168.86.0/24` |

A simple [configuration example](#configuration-examples).

Further [documentation](./plugins/nebula_ca.md).

## Configuration Examples

Using a built-in CoCo AS:
Expand Down Expand Up @@ -283,6 +316,13 @@ policy_engine = "opa"
name = "resource"
type = "LocalFs"
dir_path = "/opt/confidential-containers/kbs/repository"

[[plugins]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we add a separate config example for nebula and leave this only for CoCoAS example?

name = "nebula-ca"
# This sub-section is optional. In this example, we just
# want to show how to customize the Nebula CA.
[plugin.self_signed_ca]
duration = "4380hm0s0"
```

Using a remote CoCo AS:
Expand All @@ -302,6 +342,13 @@ as_addr = "http://127.0.0.1:50004"
name = "resource"
type = "LocalFs"
dir_path = "/opt/confidential-containers/kbs/repository"

[[plugins]]
name = "nebula-ca"
nebula_cert_bin_path = "/usr/local/bin/nebula-cert"
work_dir = "/opt/confidential-containers/kbs/nebula-ca"
[plugins.settings]
name = "Nebula CA for Trustee KBS"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same suggestion as before.

```

Running with Intel Trust Authority attestation service:
Expand Down
72 changes: 72 additions & 0 deletions kbs/docs/plugins/nebula_ca.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Nebula CA plugin

[Nebula](https://github.com/slackhq/nebula) is an open-source project that provides
tooling to create a Layer 3 Encrypted Nebula Overlay Network (ENON). Each Nebula release
provides two binaries.
- nebula: it's used to create nodes (Lighthouse or regular node) and
join to a Lighthouse's ENON
- nebula-cert: executable to generate keys, certificates, CA's, and to sign node certificates.

This plugin calls the `nebula-cert` binary to provide some of its functionalities for
Nebula nodes (e.g. CoCo PODs or confidential VMs) that want to join an ENON.

Every ENON must have at least one Lighthouse, which is a node that has an static IP address, identifies the ENON and helps with node discovery.

## Setup

Build the KBS with the cargo feature `nebula-ca-plugin` enabled and install the `nebula-cert` binary to the KBS image.

```bash
docker compose build --build-arg NEBULA_CA_PLUGIN=true
```

Configure the `nebula-ca` plugin. For simple cases, the plugin default configurations should be enough, just add the lines below to the [KBS config](#kbs/config/docker-compose/kbs-config.toml). For more complex cases, the [config.md](#kbs/docs/config.md) explains how the plugin could be customized.

```toml
[[plugins]]
name = "nebula-ca"
```

Start trustee

```bash
docker compose up
```

## Runtime services

All runtime services supported are described in the following sections.

### credential service

Create a credential for the node to join an ENON.

Only `GET` request is supported, e.g. `GET /kbs/v0/nebula-ca/credential?name=podA&ip=10.9.8.7/21`.

The request takes parameters via URL query string. All parameters supported are described in the table below. Note that `name` and `ip` are required.

| Property | Type | Required | Description | Default | Example |
|---------------------|--------|----------|-------------------------|---------|-------------------------------------------|
| `name` | String | Yes | Name of the certificate, usually hostname or podname | | `credential?name=podA&ip=10.9.8.7/21` |
| `ip` | String | Yes | IPv4 address and network in CIDR notation to assign to the certificate | | `credential?name=podA&ip=10.9.8.7/21` |
| `duration` | String | No | How long the certificate should be valid for. | 1 second before the signing certificate expires. Valid time units are: <hours>"h"<minutes>"m"<seconds>"s" | `credential?name=podA&ip=10.9.8.7/21&duration=8760h0m0s` |
| `groups` | String | No | Comma separated list of groups | | `credential?name=podA&ip=10.9.8.7/21&groups=ssh,server` |
| `subnets` | String | No | Comma separated list of IPv4 address and network in CIDR notation. Subnets the certificate can serve for. | | `credential?name=podA&ip=10.9.8.7/21&subnets=10.9.7.7/21,10.9.8.7/21` |

The request will be processed only if the node passes the attestation, otherwise an error is returned. With that, the ENON is expected to have only attested nodes.

Once the request is processed, the following structure is returned in JSON format.

```rust
struct CredentialServiceOut {
node_crt: Vec<u8>, // Self-signed certificate created
node_key: Vec<u8>, // Key created
ca_crt: Vec<u8>, // CA certificate
}
```

Currently, this service provides only basic functionality.
- It is stateless. Once a requested credential is returned, it is deleted.
- It does not support [CA rotation](https://nebula.defined.net/docs/guides/rotating-certificate-authority/).
- It does not support runtime attestation. If the same POD requests another credential later, the changes made to the POD's initial state will not be attested. Ideally, the POD should make sure that the certificate will not expire before the workload is finished.
- It does not have any information about Lighthouses, so it is not able to check if the IP address provided in the request and the IP address of the Lighthouse are in the same network.
4 changes: 4 additions & 0 deletions kbs/src/plugins/implementations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#[cfg(feature = "nebula-ca-plugin")]
pub mod nebula_ca;
pub mod resource;
pub mod sample;

#[cfg(feature = "nebula-ca-plugin")]
pub use nebula_ca::{NebulaCaPlugin, NebulaCaPluginConfig};
pub use resource::{RepositoryConfig, ResourceStorage};
pub use sample::{Sample, SampleConfig};
Loading
Loading