Gateway-to-CP mTLS

For: Platform engineers and security teams operating self-hosted gateways.

Security Overview | mTLS | Bundle Signing | Credential Encryption

Axemere Gateway uses mutual TLS (mTLS) to authenticate self-hosted gateways to the Axemere Control Plane. Every gRPC call from a gateway to the CP carries a client certificate; the CP rejects connections from any node that cannot present a valid cert issued by the Axemere CA.

Managed Gateway: mTLS is handled automatically for Axemere-hosted gateways. This guide applies to self-hosted deployments only.

Table of Contents


How It Works

Control PlaneGateway NodeControl PlaneGateway NodeFirst startup with MVGC_BOOTSTRAP_TOKENSubsequent startupsGenerate ECDSA P-256 key pair + CSRRegisterGateway(bootstrap_token, CSR)Validate token, sign CSR with Axemere CAnode_cert (90-day), ca_bundleStore cert + CA bundle in MVGC_KEY_DIRgRPC (presents node_cert as client cert)Verify cert chain to Axemere CAConnection accepted

The private key is generated on the gateway and never transmitted. The control plane receives only a Certificate Signing Request (CSR) and returns a signed certificate.


Enrollment Flow

Enrollment happens automatically on first startup when MVGC_BOOTSTRAP_TOKEN is set.

Step 1 — Generate a bootstrap token in the Console

  1. Sign in at console.axemere.ai
  2. Go to Gateways in the left sidebar
  3. Click Enroll NodeGenerate Enrollment Token
  4. Choose an expiry (default: 24 hours)
  5. Copy the token; it is shown only once

Step 2 — Start the gateway with the token

Via environment variables:

export MVGC_BOOTSTRAP_TOKEN="<token from console>"
export MVGC_CP_ADDR="gcp.cp.axemere.ai:9090"
export MVGC_ORG_ID="<your org_id>"
export MVGC_KEY_DIR="/var/lib/mvgc/keys"

./mvgc-gateway

Or equivalently in mvgc.yaml (see Config File):

control_plane:
  addr: "gcp.cp.axemere.ai:9090"
  bootstrap_token: "<token from console>"

gateway:
  org_id: "<your org_id>"

security:
  key_dir: "/var/lib/mvgc/keys"

bootstrap_token is consumed on first successful enrollment and cleared automatically; it does not need to be removed from the config file manually.

Step 3 — Verify enrollment

curl -s http://localhost:7080/healthz | jq '{cp_status, node_id}'
# → {"cp_status":"connected","node_id":"gw-node-prod-01"}

cp_status must be "connected". If it shows "unconfigured" or "offline", check the environment variables and that the bootstrap token has not expired.


Certificate Lifecycle

MVGC_BOOTSTRAP_TOKEN present

CSR signed by CP CA, cert stored in MVGC_KEY_DIR

Within 14 days of expiry

Auto-renewed, old cert valid during overlap

Admin calls RevokeGatewayCert

90-day TTL elapsed, gateway goes offline

New bootstrap token required

Bootstrap

Active

RenewalWindow

Revoked

Expired

Initial Enrollment

  • Certificate validity: 90 days
  • Algorithm: ECDSA P-256
  • CN format: mvgc-gw.<org_id>.<node_id>

Automatic Renewal

The gateway monitors its certificate expiry. When fewer than 14 days remain:

  1. A new key pair + CSR is generated
  2. A renewal request is sent to the CP, authenticated with the current cert
  3. The CP issues a new 90-day cert
  4. The old cert remains valid until it expires to avoid disruption during rollout

No operator action required.

Manual Renewal

To renew early (e.g., after a security event):

  1. Generate a new bootstrap token in the console
  2. Set MVGC_BOOTSTRAP_TOKEN to the new token
  3. Restart the gateway; enrollment runs again and issues a new cert

PKI Architecture

Axemere Root CA
(offline, air-gapped)

Axemere Intermediate CA
(GCP Cloud KMS)

Gateway Node Cert
ECDSA P-256, 90 days

LevelKey typeStorageValidity
Root CARSA 4096Air-gapped (offline)10 years
Intermediate CAECDSA P-384GCP Cloud KMS2 years
Gateway node certECDSA P-256MVGC_KEY_DIR on gateway90 days

The root CA signs the intermediate CA. The intermediate CA signs gateway node certificates. The root key is never used in automated flows.


Revocation

To revoke a gateway certificate (e.g., decommissioning a node or suspending an org):

From the Console:

  1. Go to Gateways in the left sidebar
  2. Find the node and click Revoke Certificate

From the CLI:

mvgc gateways revoke --node-id gw-node-prod-01

After revocation, the gateway's next gRPC call will be rejected with codes.PermissionDenied. The gateway falls back to cached policy and continues serving requests from cache until the cache TTL expires or the gateway is restarted.


Key Security Properties

PropertyGuarantee
Private key confidentialityPrivate key generated on gateway, never transmitted
CP authenticationOnly certs signed by Axemere CA accepted
Org isolationOrg identity bound to certificate, cannot be spoofed at the application layer
RevocationCertificate immediately rejected on next connection
Forward secrecyTLS 1.3 with ECDHE, session keys not derived from cert key

Environment Variables

VariableDefaultDescription
MVGC_BOOTSTRAP_TOKENSingle-use enrollment token from console. Used only on first startup.
MVGC_CP_ADDRControl plane gRPC address, e.g. gcp.cp.axemere.ai:9090
MVGC_KEY_DIR./keysDirectory where the gateway stores its cert, private key, and CA bundle
MVGC_CP_CA_CERTOverride: path to CA cert file (skips auto-provisioned CA bundle)
MVGC_NODE_CERTOverride: path to node cert file (skips auto-provisioned cert)
MVGC_NODE_CERT_KEYOverride: path to node private key file

Setting MVGC_CP_CA_CERT, MVGC_NODE_CERT, and MVGC_NODE_CERT_KEY together disables automatic enrollment and uses the provided files instead.


Troubleshooting

SymptomLikely causeFix
cp_status: "unconfigured"MVGC_CP_ADDR not set or MVGC_BOOTSTRAP_TOKEN missingSet both env vars and restart
cp_status: "offline" after enrollmentNetwork blocked or cert validation failingCheck firewall rules on port 9090; inspect gateway logs for TLS errors
codes.PermissionDenied on gRPCCertificate revoked or org suspendedGenerate a new bootstrap token; check org status in console
cert expiry warning in logsCertificate within 14-day renewal windowRenewal is automatic; check that CP is reachable
Gateway stuck in "enrolling"Bootstrap token expiredGenerate a new token and restart

See Also