convoy docs
Search

Cluster auth providers

How convoy builds the connection to a target cluster and how the source controllers authenticate.

The package internal/clusterconn makes a rest.Config for the target cluster of a Cluster. The cluster controller, the release controller and the observer use it. The source controllers do not use it. Each source kind has its own credential code. All of them read credentials with the package internal/auth. For the auth types of each kind, see Credentials.

Connector#

Connector.Connect selects the connection by spec.connectionMode:

ModeResult
inClusterThe rest.Config of the convoy process itself.
agentlessThe authenticator in the registry for spec.agentless.auth.type makes the config.
agentErrUnsupported. Not built
Other valueErrUnsupported

For inCluster, the config is the config that the manager built at start. That is the in-cluster service account config, or the --kubeconfig file when that flag is set. Thus with --kubeconfig, an inCluster Cluster targets the cluster of that file.

Connector.DynamicClients calls Connect and then makes a dynamic client and a RESTMapper from discovery. It does this at each call. There is no cache of clients or credentials. The deployer, the hook runner and the observer use DynamicClients. The cluster prober uses Connect and then reads the server version and the API groups.

Authenticator registry#

clusterconn.Registry maps an auth type to an Authenticator. Both managers make the same registry with one entry:

go
clusterAuth := clusterconn.Registry{
    corev1alpha1.ClusterAuthTypeKubeconfig: auth.KubeconfigAuthenticator{},
}

KubeconfigAuthenticator reads the Secret spec.agentless.auth.kubeconfig.secretRef in the namespace of the Cluster. It parses the key with clientcmd.RESTConfigFromKubeConfig. The kubeconfig gives the server, the CA and the credentials. The authenticator ignores the server and the CA fields of the Cluster.

Error classes#

Connect returns errors in two classes:

ErrorCauseCluster Ready reasonRetry
clusterconn.ErrUnsupportedMode agent, an unknown mode, or an auth type that is not in the registryUnsupportedNo. The cluster controller returns no error.
clusterconn.ErrProbeFailedThe authenticator failed, for example a missing Secret or key, or spec.agentless is emptyProbeFailedYes, with the rate limiter of the queue

The prober adds ErrProbeFailed to discovery errors. An error without a class also gives reason ProbeFailed. The release controller applies only to a Cluster with status.reachable: true. If the deployer returns clusterconn.ErrUnsupported, the Applied reason is Unsupported and convoy does not retry. Other deploy errors give DeployFailed and a retry.

Secret and ConfigMap resolution#

auth.SecretResolver reads Secrets and ConfigMaps with a direct GET to the host cluster. It does not use an informer cache. Each reference is local to the namespace of the object that contains it.

  • ResolveSecretKey reads one key from Secret.data.
  • ResolveConfigMapKey reads one key from ConfigMap.data, then from ConfigMap.binaryData.
  • A missing name, object or key gives an error that names the object and the key.

Source authentication#

Each source kind has its own resolveAuth or authMethod function, with its own ErrUnsupported and ErrFetchFailed errors. ErrUnsupported gives reason Unsupported and no retry. Other errors give reason VerifyFailed and a retry.

KindTypeCredential on the wire
GitRepositorybasicHTTP basic auth with username and the password from the Secret
GitRepositorytokenHTTP basic auth with user git and the token as password
GitRepositorysshKeySSH public key auth with user git, with host key verification
HelmRegistrybasicHTTP basic auth on each request
HelmRegistrytokenAuthorization: Bearer <token> on each request
OCIRegistrybasicRegistry login with username and the password
OCIRegistrytokenRegistry login with user convoy and the token as password

All three kinds accept none. Each other type returns ErrUnsupported. A selected type without its configuration block also returns ErrUnsupported. A Secret read error gives ErrFetchFailed for Helm and OCI. For Git, the error has no class, so the result is also VerifyFailed and a retry.

The verify step differs between the kinds:

  • Git runs ls-remote. It verifies the address and the credentials.
  • Helm downloads index.yaml with the credentials.
  • OCI sends GET https://<host>/v2/. A 200 or a 401 passes. Thus the verify step does not verify the OCI credentials. convoy verifies the credentials at the first pull.

For Helm, the fetch sends the credentials also to the chart URL from index.yaml. That URL can be on a different host than the registry.

SSH host keys#

sshKey auth requires knownHostsRef. There is no mode that skips the host key verification. knownHostsCallback parses the known_hosts data in memory and writes no file:

  • It accepts plaintext host entries, more than one key type for each host, and @revoked entries.
  • It rejects hashed entries (|1|…) with ErrUnsupported.
  • It skips @cert-authority entries. CA-based host verification is not supported.
  • Data with no usable entry gives ErrUnsupported.

At connection time, the callback compares the presented key with the entries of the host. A @revoked match fails. A host with entries but no matching key fails with a host key mismatch. A host with no entry fails.

TLS#

For Git, Helm and OCI, convoy reads only tls.insecureSkipVerify. It does not read tls.caPublicCertRef. A source with a private CA must use a certificate that the system trust store accepts, or skip the verification.

Planned providers#

These Cluster auth types are in the API but not in the registry: token, clientCert, execPlugin and oidc. A Cluster with one of them has reason Unsupported. Not built

The planned execPlugin design calls a separate credential provider workload over the network. It does not start a local process. Not built

In the code

convoy v0.9.0