Skip to content

Latest commit

 

History

History
 
 

README.md

Gencred

Description

gencred is a simple tool used to generate cluster auth credentials (w/ cluster-admin permissions) for authenticating to a Kubernetes cluster.

NOTE: since gencred creates credentials with cluster-admin level access, the kube context used must also be bound to the cluster-admin role.

Usage

Script

Run using Bazel:

$ bazel run //gencred -- <options>

Run using Golang:

$ go run k8s.io/test-infra/gencred <options>

The following is a list of supported options for the gencred CLI. All options are optional.

  -c, --certificate      Authorize with a client certificate and key.
      --context string   The name of the kubeconfig context to use.
  -n, --name string      Context name for the kubeconfig entry. (default "build")
  -o, --output string    Output path for generated kubeconfig file. (default "/dev/stdout")
      --overwrite        Overwrite (rather than merge) output file if exists.
  -s, --serviceaccount   Authorize with a service account. (default true)

Create a kubeconfig entry with context name mycluster using serviceaccount authorization and output to a file config.yaml.

serviceaccount authorization is the default if neither -s, --serviceaccount nor -c, --certificate is specified.

$ gencred --context my-current-context --name mycluster --output ./config.yaml --serviceaccount

The kubeconfig contents will be output to ./config.yaml:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: fake-ca-data
    server: https://1.2.3.4
  name: mycluster
contexts:
- context:
    cluster: mycluster
    user: mycluster
  name: mycluster
current-context: mycluster
kind: Config
preferences: {}
users:
- name: mycluster
  user:
    token: fake-token

Create a kubeconfig entry with default context name build using certificate authorization and output to the default stdout.

$ gencred --context my-current-context --certificate

The kubeconfig contents will be output to stdout:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: fake-ca-data
    server: https://1.2.3.4
  name: build
contexts:
- context:
    cluster: build
    user: build
  name: build
current-context: build
kind: Config
preferences: {}
users:
- name: build
  user:
    client-certificate-data: fake-cert-data
    client-key-data: fake-key-data

Specify the --overwrite flag to replace the output file if it exists.

$ gencred --context my-current-context --output ./existing.yaml --overwrite

Omit the --overwrite flag to merge the output file if it exists.

Entries from the existing file take precedence on conflicts.

$ gencred --context my-current-context --name oldcluster --output ./existing.yaml
$ gencred --context my-current-context --name newcluster --output ./existing.yaml

The kubeconfig contents will be output to ./existing.yaml:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: fake-ca-data
    server: https://1.2.3.4
  name: oldcluster
- cluster:
    certificate-authority-data: fake-ca-data
    server: https://1.2.3.4
  name: newcluster
contexts:
- context:
    cluster: oldcluster
    user: oldcluster
  name: oldcluster
- context:
    cluster: newcluster
    user: newcluster
  name: newcluster
users:
- name: oldcluster
  user:
    client-certificate-data: fake-cert-data
    client-key-data: fake-key-data
- name: newcluster
  user:
    client-certificate-data: fake-cert-data
    client-key-data: fake-key-data

Merging into a kubeconfig in a Kubernetes secret.

If you store kubeconfig files in kubernetes secrets to allow pods to access other kubernetes clusters (like many of Prow's components require) consider using merge_kubeconfig_secret.py to merge the kubeconfig produced by gencred into the secret.

# Generate a kubeconfig.yaml as described and shown above, then run something like:
./merge_kubeconfig_secret.py --src-key=config-old --dest-key=config-new kubeconfig.yaml
# Update references (e.g. `--kubeconfig` flags) to point to config-new instead of config-old.

Library

Generate a service account token for a cluster.

PREFERRED method.

// Import serviceaccount
import "k8s.io/test-infra/gencred/pkg/serviceaccount"

//...

// Create a Kubernetes clientset for interacting with the cluster.
// In this case we are simply using the `current-context` defined in our local `~/.kube/config`.
homedir, _ := os.UserHomeDir()
kubeconfig := filepath.Join(homedir, ".kube", "config")
config, _ := clientcmd.BuildConfigFromFlags("", kubeconfig)
clientset, _ := kubernetes.NewForConfig(config)

// Generate a service account token, as well as return the certificate authority that issued the token.
token, caPEM, err := serviceaccount.CreateClusterServiceAccountCredentials(clientset)

token will contain the service account access token and caPEM will contain the server certificate authority.

import "encoding/base64"

//...

// Cast the `token` to a string to use in a kubeconfig.
accessToken := string(token)
// Base64 encode the `caPEM` to use in a kubeconfig.
ca := base64.StdEncoding.EncodeToString(caPEM)

fmt.Println("token:", accessToken)
fmt.Println("ca:", ca)
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3Mit...
ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURER...

Generate a client key and certificate for a cluster.

DEPRECATED method.

// Import certificate
import "k8s.io/test-infra/gencred/pkg/certificate"

//...

// Create a Kubernetes clientset for interacting with the cluster.
// In this case we are simply using the `current-context` defined in our local `~/.kube/config`.
homedir, _ := os.UserHomeDir()
kubeconfig := filepath.Join(homedir, ".kube", "config")
config, _ := clientcmd.BuildConfigFromFlags("", kubeconfig)
clientset, _ := kubernetes.NewForConfig(config)

// Generate a client key and certificate, as well as return the certificate authority that issued the certificate.
certPEM, keyPEM, caPEM, err := certificate.CreateClusterCertificateCredentials(clientset)

certPEM will contain the client certificate, keyPEM will contain the client key, and caPEM will contain the server certificate authority.

import "encoding/base64"

//...

// Base64 encode the `certPEM`, `keyPEM`, and `caPEM` to use in a kubeconfig.
cert := base64.StdEncoding.EncodeToString(certPEM)
key := base64.StdEncoding.EncodeToString(keyPEM)
ca := base64.StdEncoding.EncodeToString(caPEM)

fmt.Println("cert:", cert)
fmt.Println("key:", key)
fmt.Println("ca:", ca)
cert: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1...
key: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNL...
ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURER...

Caveats to using client certificates:

  • The use of x509 client certificate with super-user privileges for cluster authentication/authorization has several drawbacks:

    • Certificates cannot be revoked (kubernetes/kubernetes#60917)
    • Authorization roles are essentially global and thus cannot be tweaked at the node level.
    • Unless setup with near expiry and explicit rotation, certificates are long-lived and increase the risk of exposure.
  • Client certificate authentication will be deprecated in future versions of Prow (kubernetes/test-infra#13972).