Authentication and Authorization

This outline describes authentication and authorization mechanisms within the client-go library for interacting with Kubernetes clusters. client-go provides support for various methods, including:

In-Cluster Authentication

  • Service Account Tokens: This method leverages the ServiceAccount token mounted in pods at /var/run/secrets/kubernetes.io/serviceaccount. client-go automatically uses this token when rest.InClusterConfig() is employed.
  • Example: The in-cluster-client-configuration example showcases authentication within a Kubernetes cluster.

Out-of-Cluster Authentication

  • Kubeconfig File: Authentication from outside a cluster is achieved using a kubeconfig file, which contains context information for connecting to the Kubernetes cluster. This file is also used by the kubectl command-line tool for authentication.
  • Example: The out-of-cluster-client-configuration example illustrates the use of a kubeconfig file for authentication from outside the cluster.

Authentication Plugins

client-go provides plugins that can be used for obtaining credentials from external sources. These plugins are not loaded by default and need to be imported explicitly.

  • Loading All Plugins:
    import _ "k8s.io/client-go/plugin/pkg/client/auth"
              
  • Loading Specific Plugins:
    import _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
              import _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
              import _ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
              

Authorization

client-go supports various authorization mechanisms, including:

  • Impersonation: Allows a client to perform operations as a different user.

    // ImpersonationConfig has all the available impersonation options
              type ImpersonationConfig struct {
                  // UserName is the username to impersonate on each request.
                  UserName string
                  // UID is a unique value that identifies the user.
                  UID string
                  // Groups are the groups to impersonate on each request.
                  Groups []string
                  // Extra is a free-form field which can be used to link some authentication information
                  // to authorization information.  This field allows you to impersonate it.
                  Extra map[string][]string
              }
              
  • Subject Access Reviews: Allow a client to check if a user has access to a specific resource.

    /*
              
              type AuthorizationV1Interface interface {
                  RESTClient() rest.Interface
                  LocalSubjectAccessReviewsGetter
                  SelfSubjectAccessReviewsGetter
                  SelfSubjectRulesReviewsGetter
                  SubjectAccessReviewsGetter
              }
              

Authentication Provider Interface

The AuthProvider interface defines how plugins interact with the client-go transport layer:

  /*
            
            type AuthProvider interface {
                // WrapTransport allows the plugin to create a modified RoundTripper that
                // attaches authorization headers (or other info) to requests.
                WrapTransport(http.RoundTripper) http.RoundTripper
                // Login allows the plugin to initialize its configuration. It must not
                // require direct user interaction.
                Login() error
            }
            
          

Exec Plugin Authentication

The Exec plugin provides a mechanism for obtaining credentials from an external process or service:

  • Credential Refreshing: The plugin automatically refreshes credentials if they expire.
    func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
                  // If a user has already set credentials, use that. This makes commands like
                  // "kubectl get --token (token) pods" work.
                  if req.Header.Get("Authorization") != "" {
                      return r.base.RoundTrip(req)
                  }
              
                  creds, err := r.a.getCreds()
                  if err != nil {
                      return nil, fmt.Errorf("getting credentials: %v", err)
                  }
                  if creds.token != "" {
                      req.Header.Set("Authorization", "Bearer "+creds.token)
                  }
              
                  res, err := r.base.RoundTrip(req)
                  if err != nil {
                      return nil, err
                  }
                  if res.StatusCode == http.StatusUnauthorized {
                      if err := r.a.maybeRefreshCreds(creds); err != nil {
                          klog.Errorf("refreshing credentials: %v", err)
                      }
                  }
                  return res, nil
              }
              
              type roundTripper struct {
                  a    *Authenticator
                  base http.RoundTripper
              }
              
              func (c *cache) get(s string) (*Authenticator, bool) {
                  c.mu.Lock()
                  defer c.mu.Unlock()
                  a, ok := c.m[s]
                  return a, ok
              }
              
  • Credential Storage: Credentials are stored in a secure manner within the plugin.
    // ExecCredentialStatus holds credentials for the transport to use.
              //
              // Token and ClientKeyData are sensitive fields. This data should only be
              // transmitted in-memory between client and exec plugin process. Exec plugin
              // itself should at least be protected via file permissions.
              type ExecCredentialStatus struct {
                  // ExpirationTimestamp indicates a time when the provided credentials expire.
                  // +optional
                  ExpirationTimestamp *metav1.Time `json:"expirationTimestamp,omitempty"`
                  // Token is a bearer token used by the client for request authentication.
                  Token string `json:"token,omitempty" datapolicy:"token"`
                  // PEM-encoded client TLS certificates (including intermediates, if any).
                  ClientCertificateData string `json:"clientCertificateData,omitempty"`
                  // PEM-encoded private key for the above certificate.
                  ClientKeyData string `json:"clientKeyData,omitempty" datapolicy:"security-key"`
              }
              
  • Prompting for Credentials: The plugin can prompt the user for credentials if they are not available.
    // LoadAuth parses an AuthInfo object from a file path. It prompts user and creates file if it doesn't exist.
              func (a *PromptingAuthLoader) LoadAuth(path string) (*clientauth.Info, error) {
                  // Prompt for user/pass and write a file if none exists.
                  if _, err := os.Stat(path); os.IsNotExist(err) {
                      authPtr, err := a.Prompt()
                      if err != nil {
                          return nil, err
                      }
                      auth := *authPtr
                      data, err := json.Marshal(auth)
                      if err != nil {
                          return &auth, err
                      }
                      err = os.WriteFile(path, data, 0600)
                      return &auth, err
                  }
                  authPtr, err := clientauth.LoadFromFile(path)
                  if err != nil {
                      return nil, err
                  }
                  return authPtr, nil
              }
              
  • Transport Layer Integration: The plugin modifies the RoundTripper to attach authentication information to requests.
    // maskValue masks credential content from authorization headers
              // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
              func maskValue(key string, value string) string {
                  if !strings.EqualFold(key, "Authorization") {
                      return value
                  }
                  if len(value) == 0 {
                      return ""
                  }
                  var authType string
                  if i := strings.Index(value, " "); i > 0 {
                      authType = value[0:i]
                  } else {
                      authType = value
                  }
                  if !knownAuthTypes[strings.ToLower(authType)] {
                      return ""
                  }
                  if len(value) > len(authType)+1 {
                      value = authType + " "
                  } else {
                      value = authType
                  }
                  return value
              }
              

Example: Managing Deployments

The create-update-delete-deployment example demonstrates managing Kubernetes Deployment resources. This example covers fundamental operations like creating, listing, updating, and deleting resources via the Kubernetes API.

Other Resources

The client-go library offers various resources and functionalities, including:

  • kubernetes package: Provides the clientset for accessing the Kubernetes API.
  • discovery package: Enables discovery of APIs supported by a Kubernetes API server.
  • dynamic package: Offers a dynamic client for performing generic operations on arbitrary Kubernetes API objects.
  • plugin/pkg/client/auth packages: Contain optional authentication plugins for obtaining credentials from external sources.
  • transport package: Used to set up authentication and initiate connections.
  • tools/cache package: Useful for developing controllers.

Additional Examples

The client-go repository includes various examples:

  • fake-client: Using a fake client in tests.
  • work-queues: Creating a hotloop-free controller using a rate-limited work queue and the informer framework.
  • custom-resource-definition: Registering a custom resource type with the API, performing CRUD operations on this custom type, and writing a controller based on custom resource changes.
  • leader-election: Implementing HA controllers using the leader election package.

References

Top-Level Directory Explanations

applyconfigurations/ - This directory contains examples and tests for applying Kubernetes configurations using the client-go library.

discovery/ - This directory contains code related to service discovery in Kubernetes.

informers/ - This directory contains code for caching Kubernetes resources using informers.

kubernetes/ - This directory contains the main package for the client-go library, which provides types and functions for interacting with the Kubernetes API.

listers/ - This directory contains interfaces and implementations for listing Kubernetes resources.

openapi/ - This directory contains OpenAPI definitions for the Kubernetes API.

pkg/ - This directory contains compiled Go packages for the client-go library.

plugin/ - This directory contains code for loading plugins for the client-go library.

rest/ - This directory contains code for working with the REST API in the client-go library.

tools/ - This directory contains various tools for working with the client-go library.

util/ - This directory contains utility functions for the client-go library.