From d032e0565263c0f9641736f21af21c2b1e897546 Mon Sep 17 00:00:00 2001 From: Qi Guo <979918879@qq.com> Date: Tue, 28 Apr 2026 19:07:24 +0800 Subject: [PATCH 1/4] docs: align mtls skill with service model --- skills/a7-recipe-mtls/SKILL.md | 145 ++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 55 deletions(-) diff --git a/skills/a7-recipe-mtls/SKILL.md b/skills/a7-recipe-mtls/SKILL.md index 24f995f..2d60af6 100644 --- a/skills/a7-recipe-mtls/SKILL.md +++ b/skills/a7-recipe-mtls/SKILL.md @@ -17,7 +17,7 @@ metadata: - a7 ssl list - a7 ssl get - a7 ssl delete - - a7 upstream create + - a7 service create - a7 route create --- @@ -74,25 +74,41 @@ EOF - `client.ca`: CA certificate used to verify client certificates. - `client.depth`: (optional) Maximum certificate chain depth for verification. -### 2. Create a route on the protected domain +### 2. Create a service for the protected backend ```bash -a7 route create --gateway-group default -f - <<'EOF' +a7 service create --gateway-group default -f - <<'EOF' { - "id": "secure-api", - "uri": "/api/*", - "host": "api.example.com", + "id": "secure-api-service", + "name": "secure-api-service", "upstream": { "type": "roundrobin", - "nodes": { - "backend:8080": 1 - } + "nodes": [ + { + "host": "backend", + "port": 8080, + "weight": 1 + } + ] } } EOF ``` -### 3. Test with client certificate +### 3. Create a route on the protected domain + +```bash +a7 route create --gateway-group default -f - <<'EOF' +{ + "id": "secure-api", + "paths": ["/api/*"], + "host": "api.example.com", + "service_id": "secure-api-service" +} +EOF +``` + +### 4. Test with client certificate ```bash # With valid client cert — succeeds @@ -107,20 +123,27 @@ curl --cacert ca.crt https://api.example.com:9443/api/health Configure API7 EE to present a client certificate when connecting to backends. -### 1. Create upstream with TLS client certificate +### 1. Create service with TLS client certificate ```bash -a7 upstream create --gateway-group default -f - <<'EOF' +a7 service create --gateway-group default -f - <<'EOF' { - "id": "mtls-backend", - "type": "roundrobin", - "scheme": "https", - "nodes": { - "secure-backend:443": 1 - }, - "tls": { - "client_cert": "", - "client_key": "" + "id": "mtls-backend-service", + "name": "mtls-backend-service", + "upstream": { + "type": "roundrobin", + "scheme": "https", + "nodes": [ + { + "host": "secure-backend", + "port": 443, + "weight": 1 + } + ], + "tls": { + "client_cert": "", + "client_key": "" + } } } EOF @@ -132,14 +155,14 @@ EOF - `tls.client_key`: Private key for the client certificate. - `pass_host`: Set to `"pass"` (default) or `"rewrite"` if upstream expects a specific Host header. -### 2. Create route using this upstream +### 2. Create route using this service ```bash a7 route create --gateway-group default -f - <<'EOF' { "id": "api", - "uri": "/api/*", - "upstream_id": "mtls-backend" + "paths": ["/api/*"], + "service_id": "mtls-backend-service" } EOF ``` @@ -165,20 +188,27 @@ a7 ssl create --gateway-group default -f - <<'EOF' EOF ``` -### 2. Upstream for API7 EE → backend mTLS +### 2. Service for API7 EE → backend mTLS ```bash -a7 upstream create --gateway-group default -f - <<'EOF' +a7 service create --gateway-group default -f - <<'EOF' { - "id": "secure-backend", - "type": "roundrobin", - "scheme": "https", - "nodes": { - "internal-service:443": 1 - }, - "tls": { - "client_cert": "", - "client_key": "" + "id": "secure-backend-service", + "name": "secure-backend-service", + "upstream": { + "type": "roundrobin", + "scheme": "https", + "nodes": [ + { + "host": "internal-service", + "port": 443, + "weight": 1 + } + ], + "tls": { + "client_cert": "", + "client_key": "" + } } } EOF @@ -190,9 +220,9 @@ EOF a7 route create --gateway-group default -f - <<'EOF' { "id": "e2e-mtls-api", - "uri": "/api/*", + "paths": ["/api/*"], "host": "api.example.com", - "upstream_id": "secure-backend" + "service_id": "secure-backend-service" } EOF ``` @@ -265,26 +295,31 @@ ssls: -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- -upstreams: - - id: secure-backend - type: roundrobin - scheme: https - nodes: - "backend:443": 1 - tls: - client_cert: | - -----BEGIN CERTIFICATE----- - - -----END CERTIFICATE----- - client_key: | - -----BEGIN RSA PRIVATE KEY----- - - -----END RSA PRIVATE KEY----- +services: + - id: secure-backend-service + name: secure-backend-service + upstream: + type: roundrobin + scheme: https + nodes: + - host: backend + port: 443 + weight: 1 + tls: + client_cert: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- + client_key: | + -----BEGIN RSA PRIVATE KEY----- + + -----END RSA PRIVATE KEY----- routes: - id: mtls-api - uri: /api/* + paths: + - /api/* host: api.example.com - upstream_id: secure-backend + service_id: secure-backend-service ``` ## Troubleshooting @@ -297,4 +332,4 @@ routes: | Certificate expired | TLS cert past validity date | Rotate certificate with `a7 ssl update` | | SNI mismatch | Domain doesn't match `snis` list | Add the domain to the `snis` array | | Command failed with 401 | Invalid token | Refresh your token using `a7 context create` | -| Upstream not found | Different gateway group | Ensure `--gateway-group` matches where resources were created | +| Service not found | Different gateway group | Ensure `--gateway-group` matches where resources were created | From 05a8ab905bd1f114b9946c57f61538d726aa8d28 Mon Sep 17 00:00:00 2001 From: Qi Guo <979918879@qq.com> Date: Tue, 28 Apr 2026 22:25:37 +0800 Subject: [PATCH 2/4] docs: address mtls skill review feedback --- skills/a7-recipe-mtls/SKILL.md | 75 +++++++++++++++------------------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/skills/a7-recipe-mtls/SKILL.md b/skills/a7-recipe-mtls/SKILL.md index 2d60af6..0b717ad 100644 --- a/skills/a7-recipe-mtls/SKILL.md +++ b/skills/a7-recipe-mtls/SKILL.md @@ -83,13 +83,9 @@ a7 service create --gateway-group default -f - <<'EOF' "name": "secure-api-service", "upstream": { "type": "roundrobin", - "nodes": [ - { - "host": "backend", - "port": 8080, - "weight": 1 - } - ] + "nodes": { + "backend:8080": 1 + } } } EOF @@ -123,7 +119,17 @@ curl --cacert ca.crt https://api.example.com:9443/api/health Configure API7 EE to present a client certificate when connecting to backends. -### 1. Create service with TLS client certificate +### 1. Prepare upstream client certificates + +Create the upstream client SSL certificate and CA certificate in API7 EE first, then note their IDs/names. The recommended API7 Enterprise workflow is: + +1. Add an SSL Certificate using the certificate API7 EE should present to the upstream. +2. Add a CA Certificate used to verify the upstream server certificate. +3. Select both certificates in the published service's upstream connection configuration. + +If you use `a7 ssl create` to upload the client SSL certificate, keep the PEM material in a local file that is not committed, and pass the file with `-f`. + +### 2. Create service with HTTPS upstream ```bash a7 service create --gateway-group default -f - <<'EOF' @@ -133,16 +139,11 @@ a7 service create --gateway-group default -f - <<'EOF' "upstream": { "type": "roundrobin", "scheme": "https", - "nodes": [ - { - "host": "secure-backend", - "port": 443, - "weight": 1 - } - ], + "nodes": { + "secure-backend:443": 1 + }, "tls": { - "client_cert": "", - "client_key": "" + "client_cert_id": "" } } } @@ -150,12 +151,14 @@ EOF ``` **Fields**: -- `scheme`: Must be `"https"` for TLS connections to upstream. -- `tls.client_cert`: Client certificate API7 EE presents to the upstream. -- `tls.client_key`: Private key for the client certificate. -- `pass_host`: Set to `"pass"` (default) or `"rewrite"` if upstream expects a specific Host header. +- `upstream.scheme`: Must be `"https"` for TLS connections to upstream. +- `upstream.nodes`: Backend nodes as `{"host:port": weight}`. +- `upstream.tls.client_cert_id`: Client certificate object API7 EE presents to the upstream. +- `upstream.pass_host`: Set to `"pass"` (default) or `"rewrite"` if upstream expects a specific Host header. + +Configure the upstream CA certificate in the published service's upstream connection configuration if API7 EE should verify the upstream server certificate. -### 2. Create route using this service +### 3. Create route using this service ```bash a7 route create --gateway-group default -f - <<'EOF' @@ -198,16 +201,11 @@ a7 service create --gateway-group default -f - <<'EOF' "upstream": { "type": "roundrobin", "scheme": "https", - "nodes": [ - { - "host": "internal-service", - "port": 443, - "weight": 1 - } - ], + "nodes": { + "internal-service:443": 1 + }, "tls": { - "client_cert": "", - "client_key": "" + "client_cert_id": "" } } } @@ -302,18 +300,9 @@ services: type: roundrobin scheme: https nodes: - - host: backend - port: 443 - weight: 1 + "backend:443": 1 tls: - client_cert: | - -----BEGIN CERTIFICATE----- - - -----END CERTIFICATE----- - client_key: | - -----BEGIN RSA PRIVATE KEY----- - - -----END RSA PRIVATE KEY----- + client_cert_id: upstream-client-cert routes: - id: mtls-api paths: @@ -328,7 +317,7 @@ routes: |---------|-------|-----| | SSL handshake failure (client side) | Client cert not signed by the CA in `client.ca` | Verify CA chain; check that client cert is signed by the correct CA | | "no required SSL certificate" | Client didn't send a certificate | Configure client to present cert (`--cert` in curl) | -| 502 to upstream | Upstream rejects API7 EE's client cert | Verify `tls.client_cert` is signed by the upstream's trusted CA | +| 502 to upstream | Upstream rejects API7 EE's client cert | Verify `upstream.tls.client_cert_id` points to a certificate signed by the upstream's trusted CA | | Certificate expired | TLS cert past validity date | Rotate certificate with `a7 ssl update` | | SNI mismatch | Domain doesn't match `snis` list | Add the domain to the `snis` array | | Command failed with 401 | Invalid token | Refresh your token using `a7 context create` | From af246199ae51b103adc15ebdcbf0b6f7da5462e9 Mon Sep 17 00:00:00 2001 From: Qi Guo <979918879@qq.com> Date: Tue, 28 Apr 2026 22:58:23 +0800 Subject: [PATCH 3/4] docs: fix mtls skill grammar --- skills/a7-recipe-mtls/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/a7-recipe-mtls/SKILL.md b/skills/a7-recipe-mtls/SKILL.md index 0b717ad..4394fcd 100644 --- a/skills/a7-recipe-mtls/SKILL.md +++ b/skills/a7-recipe-mtls/SKILL.md @@ -123,7 +123,7 @@ Configure API7 EE to present a client certificate when connecting to backends. Create the upstream client SSL certificate and CA certificate in API7 EE first, then note their IDs/names. The recommended API7 Enterprise workflow is: -1. Add an SSL Certificate using the certificate API7 EE should present to the upstream. +1. Add an SSL Certificate using the certificate that API7 EE should present to the upstream. 2. Add a CA Certificate used to verify the upstream server certificate. 3. Select both certificates in the published service's upstream connection configuration. From 002f1b12682e09270e313d02c7d34ac65d0993ce Mon Sep 17 00:00:00 2001 From: Qi Guo <979918879@qq.com> Date: Tue, 28 Apr 2026 23:15:44 +0800 Subject: [PATCH 4/4] docs: align mtls service nodes with tests --- skills/a7-recipe-mtls/SKILL.md | 36 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/skills/a7-recipe-mtls/SKILL.md b/skills/a7-recipe-mtls/SKILL.md index 4394fcd..333bb38 100644 --- a/skills/a7-recipe-mtls/SKILL.md +++ b/skills/a7-recipe-mtls/SKILL.md @@ -83,9 +83,13 @@ a7 service create --gateway-group default -f - <<'EOF' "name": "secure-api-service", "upstream": { "type": "roundrobin", - "nodes": { - "backend:8080": 1 - } + "nodes": [ + { + "host": "backend", + "port": 8080, + "weight": 1 + } + ] } } EOF @@ -139,9 +143,13 @@ a7 service create --gateway-group default -f - <<'EOF' "upstream": { "type": "roundrobin", "scheme": "https", - "nodes": { - "secure-backend:443": 1 - }, + "nodes": [ + { + "host": "secure-backend", + "port": 443, + "weight": 1 + } + ], "tls": { "client_cert_id": "" } @@ -152,7 +160,7 @@ EOF **Fields**: - `upstream.scheme`: Must be `"https"` for TLS connections to upstream. -- `upstream.nodes`: Backend nodes as `{"host:port": weight}`. +- `upstream.nodes`: Backend nodes as `[{ "host": "...", "port": 443, "weight": 1 }]`. - `upstream.tls.client_cert_id`: Client certificate object API7 EE presents to the upstream. - `upstream.pass_host`: Set to `"pass"` (default) or `"rewrite"` if upstream expects a specific Host header. @@ -201,9 +209,13 @@ a7 service create --gateway-group default -f - <<'EOF' "upstream": { "type": "roundrobin", "scheme": "https", - "nodes": { - "internal-service:443": 1 - }, + "nodes": [ + { + "host": "internal-service", + "port": 443, + "weight": 1 + } + ], "tls": { "client_cert_id": "" } @@ -300,7 +312,9 @@ services: type: roundrobin scheme: https nodes: - "backend:443": 1 + - host: backend + port: 443 + weight: 1 tls: client_cert_id: upstream-client-cert routes: