k3s-io/k3s · error

no certificates loaded from etcd-s3-endpoint-ca

Error message

no certificates loaded from etcd-s3-endpoint-ca

What it means

The S3 TLS setup builds a cert pool from the etcd-s3-endpoint-ca sources (file on disk and/or data from the config secret) and sets 'loaded' only when AppendCertsFromPEM accepts at least one PEM block. If every source is empty, missing, or not parseable PEM, the pool stays empty and this error is returned.

Source

Thrown at pkg/etcd/s3/s3.go:587

		// contains multiline, ascii-armored, base64-encoded certificate data - as would be produced
		// by `base64 --wrap=0 /path/to/cert.pem`. If this fails, assume the value is the path to a
		// file on disk, and try to read that.  This is backwards compatible with RKE1.
		caData, err := base64.StdEncoding.DecodeString(ca)
		if err != nil {
			caData, err = os.ReadFile(ca)
		}
		if err != nil {
			return nil, err
		}
		if certPool.AppendCertsFromPEM(caData) {
			loaded = true
		}
	}

	if loaded {
		return &tls.Config{RootCAs: certPool}, nil
	}
	return nil, errors.New("no certificates loaded from etcd-s3-endpoint-ca")
}

func bucketLookupType(endpoint, lookupType string) minio.BucketLookupType {
	switch strings.ToLower(lookupType) {
	case "dns":
		return minio.BucketLookupDNS
	case "path":
		return minio.BucketLookupPath
	}

	if strings.Contains(endpoint, "aliyun") { // backwards compatible with RKE1
		return minio.BucketLookupDNS
	}
	return minio.BucketLookupAuto
}

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Verify the file is valid PEM: openssl x509 -in ca.pem -noout -text (for bundles, check every block with awk).
  2. Ensure the value is the CA certificate (PEM, possibly a bundle), not DER and not the leaf server cert alone.
  3. If the CA comes from the config secret, confirm the secret data key and that it is mounted/decoded correctly (no double base64).

Example fix

# before: DER-encoded or truncated CA
--etcd-s3-endpoint-ca=/etc/ssl/ca.der
# after: PEM bundle, verified first
openssl x509 -in /etc/ssl/ca.pem -noout || exit 1
--etcd-s3-endpoint-ca=/etc/ssl/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

func validPEM(data []byte) bool {
	rest := data
	found := false
	var block *pem.Block
	for {
		block, rest = pem.Decode(rest)
		if block == nil {
			return found
		}
		if block.Type == "CERTIFICATE" {
			found = true
		}
	}
}

Prevention

When it happens

Trigger: Setting --etcd-s3-endpoint-ca to a path whose file is empty/truncated/not PEM, or an etcd-s3-config secret whose CA field contains base64 garbage or a DER-encoded (binary) certificate instead of PEM.

Common situations: Fetched the cert with openssl s_client without -showcerts and got a partial chain; copied the server cert instead of the CA; trailing junk before the BEGIN CERTIFICATE line; envs where the CA file is mounted empty until an init job runs.

Understand the failure class

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/d92b2b56368a21c8. Report an issue: GitHub.