Skip to content

Use the provided CA cert when verifying the license server - #82

Merged
ArnobKumarSaha merged 1 commit into
masterfrom
arnob-cacert-fix
Sep 18, 2026
Merged

ArnobKumarSaha merged 1 commit into
masterfrom
arnob-cacert-fix

Conversation

@ArnobKumarSaha

Copy link
Copy Markdown
Member

Problem

NewClient accepts a caCert []byte but never assigns it to the Client struct. The cert-pool guard then reads the always-empty c.caCert field, so tlsConfig.RootCAs is never set:

c := &Client{
    url: u, token: token, clusterUID: clusterUID,
    client: http.DefaultClient, userAgent: userAgent,   // caCert not assigned
}
if len(caCert) > 0 || insecureSkipVerifyTLS {           // parameter
    tlsConfig := &tls.Config{InsecureSkipVerify: insecureSkipVerifyTLS}
    if len(c.caCert) > 0 {                              // field -> always 0
        ...
        tlsConfig.RootCAs = caCertPool
    }
    c.client = &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
}

The outer condition still swaps in a custom transport, so a caller that passes a CA gets a client with RootCAs == nil — silently falling back to the system root pool. Against a privately-signed license server every request fails with x509: certificate signed by unknown authority. --insecure-skip-tls-verify was the only working path.

Present since #35 (Sep 2024), so --ca-file has been a no-op in every release that shipped it, including the current v0.15.0.

Real-world impact: license-proxyserver (v0.1.1 and v0.1.2, both pinned to license-verifier v0.15.0) is started with a correct --ca-file mounted from license-proxyserver-platform-auth, and still cannot reach a self-hosted ACE platform. KubeDB operators surface this as license status unknown, reason: failed to read license from proxy and crashloop.

Fix

Assign caCert to the struct, read the field consistently, and return an error when the PEM yields no usable certificate rather than dropping it silently — the silent drop is what hid this for over a year.

Verification

Against a self-hosted ACE platform (https://10.2.1.82, cert issued by a private O=ace, CN=ca), calling AcquireLicense with that CA and a dummy token:

  • before: Post "https://10.2.1.82/api/v1/license/issue": tls: failed to verify certificate: x509: "ace-nats" certificate is not trusted
  • after: the server has asked for the client to provide credentials — TLS verifies, only the dummy token is rejected

curl --cacert with the same CA from inside the cluster also returns 401, confirming the CA was always sufficient.

Notes for reviewers

Behavior change: a caller passing a malformed/non-PEM caCert now gets an error from NewClient instead of a client that fails later at request time.

NewClient never assigned the caCert argument to the Client struct, so the
guard around the cert pool read an always-empty field and RootCAs was left
nil. A custom transport was still installed, so clients passing a custom CA
silently fell back to the system roots and failed with "certificate signed
by unknown authority" against a privately-signed license server.

Assign the field and fail fast when the PEM contains no usable certificate,
instead of dropping it silently.

Signed-off-by: Arnob Kumar Saha <arnob@appscode.com>
@ArnobKumarSaha
ArnobKumarSaha merged commit bc26e23 into master Sep 18, 2026
4 checks passed
@ArnobKumarSaha
ArnobKumarSaha deleted the arnob-cacert-fix branch September 18, 2026 04:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant