Failed to enroll: expected 1 or more CAs from controller, got 0

I verified two external CAs with my controller running in the Docker Compose quickstart and got an error when I tried to auto-enroll with a client cert from the CA that has autoca enabled.

the verified external autoca CA

$ ziti edge list cas 'name="magenta"'
╭────────────────────────┬─────────┬────────┬───────┬─────────────┬───────────────────────────────────────────────────────────────╮
│ ID                     │ NAME    │ FLAGS  │ TOKEN │ FINGERPRINT │ CONFIGURATION                                                 │
├────────────────────────┼─────────┼────────┼───────┼─────────────┼───────────────┬──────────────────────┬────────────────────────┤
│ 1AmYoBfMGi5TZMLhjEyOAf │ magenta │ [VAE]  │ -     │ 4e85...32   │ AutoCA        │ Identity Name Format │ [caName]-[commonName]  │
│                        │         │        │       │             │               ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │               │ Identity Roles       │                        │
╰────────────────────────┴─────────┴────────┴───────┴─────────────┴───────────────┴──────────────────────┴────────────────────────╯
results: 1-1 of 1

Flags: (V) Verified, (A) AutoCa Enrollment, (O) OttCA Enrollment, (E) Authentication Enabled

The enrollment attempt

$ ziti edge enroll \
        --cert ~/.config/ziti/environments/pki/magenta/certs/kentest2.cert \
        --key ~/.config/ziti/environments/pki/magenta/keys/kentest2.key \
        --jwt /tmp/magenta.jwt \
        --out /tmp/kentest2.json \
        --verbose 
DEBUG   jwt to parse: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbSI6ImNhIiwiaXNzIjoiaHR0cHM6Ly96aXRpLWVkZ2UtY29udHJvbGxlcjoxMjgwLyJ9.pd8BdLDugCtijAa-c81TOJyP3qaPeA-rmSeLqatpmPgXnssfm7J905-2gsCXk_r2ASeoWgyNtBavXhDJOOCK3fZT7nNz6jhO-Zqlcn1pjb-dLG7UjLjiCf6W01Ri8n9yywS6Jm_HKv3Ysw0te_zsMe5sWrUBz3XzY1Lqg_f7bWeMRX21loSNEqjjtQz_IajHzHfJphyUeprwu4K39_CAFFujk743FWlOel0Ju1wqN6DT4mjsY4e7GLiAFGDZYaDl2qVkYoBdOcH9Md6KhdAJyahVgEazaqE6M4A6FLDJBXx9x9V2LkUtSxKQYLmStwhioOFEp-RiFmXEHnACBH2CE8dOMb8TuelBq296C0UT_2N9JqFmAWJCMnFrGIBBjt-XoiXoEFDRZlvOrp0J2C3N6OxvdmsMW5RSZmDLkW3lA_KPyxzoX1Hawb5XNNeHFRKSUD4yjU3EdTRo0-YSTJAHjuS6ys1v-iqGkGBKCUh5k-rG4g9y-Xp9Lbr6NU-8G-TNzc34ygydWoC0EDr9CME6h62wVx_48xxVOQ8h7POKTGPxZjGE63k6cbn-2iwbRpLKDH5F8GvrcAn3jcLJUVwcLJGIw9ICYuCschKeGmuVS9mBsoTfDmTGvnuUHXAm2Z4M84SIhfNqXhtSlyY17T9POvuzx7waoSBIymUx4hWMtKA 
DEBUG   fetching certificates from server            
Usage:
  ziti edge enroll path/to/jwt [flags]

Flags:
      --ca string         Additional trusted certificates
  -c, --cert string       The certificate to present when establishing a connection.
  -h, --help              help for enroll
  -n, --idname string     Names the identity. Ignored if not 3rd party auto enrollment
  -j, --jwt string        Enrollment token (JWT file). Required
  -k, --key string        The key to use with the certificate. Optionally specify the engine to use. supported engines: [parsec]
  -a, --keyAlg RSA|EC     Crypto algorithm to use when generating private key (default RSA)
  -o, --out string        Output configuration file.
  -p, --password string   Password for updb enrollment, prompted if not provided and necessary
      --rm                Remove the JWT on success
  -u, --username string   Username for updb enrollment, prompted if not provided and necessary
  -v, --verbose           Enable verbose logging


failed to enroll: expected 1 or more CAs from controller, got 0

CA enroll token

Exepectedly, the reusable autoca enroll token contains the issuer URL where the client certificate should be presented to complete enrollment.

{
  "em": "ca",
  "iss": "https://ziti-edge-controller:1280/"
}

the issuer API

Expectedly, the Ziti controller provdes its edge client API at the issuer URL.

curl -sk https://ziti-edge-controller:1280/edge/client/v1 | jq
{
  "data": {
    "apiVersions": {
      "edge": {
        "v1": {
          "apiBaseUrls": [
            "https://ziti-edge-controller:1280/edge/client/v1"
          ],
          "path": "/edge/client/v1"
        }
      },
      "edge-client": {
        "v1": {
          "apiBaseUrls": [
            "https://ziti-edge-controller:1280/edge/client/v1"
          ],
          "path": "/edge/client/v1"
        }
      },
      "edge-management": {
        "v1": {
          "apiBaseUrls": [
            "https://ziti-edge-controller:1280/edge/management/v1"
          ],
          "path": "/edge/management/v1"
        }
      }
    },
    "buildDate": "2023-06-23T15:08:25Z",
    "revision": "65d1dda821a3",
    "runtimeVersion": "go1.20.5",
    "version": "v0.28.4"
  },
  "meta": {}
}

Troubleshooting

Which client API endpoint provides the list of external CAs that the enrolling edge SDK is attempting to obtain when it emits this error?

failed to enroll: expected 1 or more CAs from controller, got 0

This error appears in the Go SDK’s enroll.go after calling ListWellKnownCas.

It appears to be the same well-known certs bundle endpoint consumed by all edge clients during enrollment of client certs from the built-in edge enrollment signer, /.well-known/est/cacerts.

I verified that ott and ottca enrollment methods succeed with ziti edge enroll CLI and do result in an identity context JSON file with appropriate values, i.e., in-line cert from edge enrollment signer for ott method, and file:// URI to cert from external CA for ottca method.

I tried autoca with Ziti 0.28.0 and obtained a different result.

$ ziti edge list cas
╭────────────────────────┬─────────┬────────┬───────┬─────────────┬─────────────────────────────────────────────────────────────────╮
│ ID                     │ NAME    │ FLAGS  │ TOKEN │ FINGERPRINT │ CONFIGURATION                                                   │
├────────────────────────┼─────────┼────────┼───────┼─────────────┼─────────────────┬──────────────────────┬────────────────────────┤
│ 7LN2KHZ7m1ZS97o1n9inJ1 │ magenta │ [VAE]  │ -     │ 79e0...1b   │ AutoCA          │ Identity Name Format │ [caName]-[commonName]  │
│                        │         │        │       │             │                 ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │                 │ Identity Roles       │                        │
│                        │         │        │       │             ├─────────────────┼──────────────────────┼────────────────────────┤
│                        │         │        │       │             │ ExternalIdClaim │ Index                │ 0                      │
│                        │         │        │       │             │                 ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │                 │ Location             │                        │
│                        │         │        │       │             │                 ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │                 │ Matcher              │                        │
│                        │         │        │       │             │                 ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │                 │ Matcher Criteria     │                        │
│                        │         │        │       │             │                 ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │                 │ Parser               │                        │
│                        │         │        │       │             │                 ├──────────────────────┼────────────────────────┤
│                        │         │        │       │             │                 │ Parser Criteria      │                        │
╰────────────────────────┴─────────┴────────┴───────┴─────────────┴─────────────────┴──────────────────────┴────────────────────────╯
results: 1-1 of 1

Flags: (V) Verified, (A) AutoCa Enrollment, (O) OttCA Enrollment, (E) Authentication Enabled

$ ziti edge enroll --cert ${ZITI_PKI_ROOT}/magenta/certs/${ZITI_CLIENT}.cert  --key ${ZITI_PKI_ROOT}/magenta/keys/${ZITI_CLIENT}.key --jwt /tmp/magenta.jwt --out /tmp/${ZITI_CLIENT}.json
Usage:
  ziti edge enroll path/to/jwt [flags]

Flags:
      --ca string         Additional trusted certificates
  -c, --cert string       The certificate to present when establishing a connection.
  -h, --help              help for enroll
  -n, --idname string     Names the identity. Ignored if not 3rd party auto enrollment
  -j, --jwt string        Enrollment token (JWT file). Required
  -k, --key string        The key to use with the certificate. Optionally specify the engine to use. supported engines: [parsec]
  -a, --keyAlg RSA|EC     Crypto algorithm to use when generating private key (default RSA)
  -o, --out string        Output configuration file.
  -p, --password string   Password for updb enrollment, prompted if not provided and necessary
      --rm                Remove the JWT on success
  -u, --username string   Username for updb enrollment, prompted if not provided and necessary
  -v, --verbose           Enable verbose logging


failed to enroll: enroll error: 400 Bad Request: MISSING_CERT_CLAIM: The certificate is expected to contain and externalId, which was not found