auth

package module
v0.0.0-...-af1ce48 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2022 License: Apache-2.0 Imports: 36 Imported by: 3

README

Auth package

Dependency free collection of helpers for mesh authentication and provisionig, for client and server. Provides helpers for client and server TLSConfig, and implements basic mesh authentication.

Usually authen/authz are focused on identity verification and access control using credentials only, however auth can provide far more value.

This package combines auth with 'bootstraping' - finding credentials AND basic metadata about the workload and its environment. It also covers tracking basic peer information - which is critical for peer authentication but also provides additional metadata about the peer.



Features:

  • dependency free implementation of Kubeconfig
  • bootstrap using platform data - workload certs, JWT tokens, etc.
  • basic deps-free OIDC parsing for JWT tokens
  • webpush VAPID JWT support and subscriptions
  • support Webpush encryption and decryption
  • basic STS and MDS support (primarily for GCP and envoy exchanges)
  • basic JWT and OIDC parsing

Dependencies and plug-ins

  • ConfStore abstracts loading/saving of the objects used for auth - file, remote call, k8s, etc

  • GetCertificateHook - for integration with CA or SDS servers.

Config

  1. Attempt to Load certificates:
  • well-known files - currently using K8S workload identity.
  • istio old location
  • current dir
  • home dir
  1. Attempt to load a k8s config

  2. Load 'acme' style DNS certs if present (for handling DNS certs)

Documentation

Overview

Package webpush provides helper functions for sending encrpyted payloads using the Web Push protocol.

Sending a message:

import (
  "strings"
  "github.com/googlechrome/webpush/webpush"
)

func main() {
  // The values that make up the Subscription struct come from the browser
  sub := &webpush.Subscription{endpoint, key, auth}
  webpush.Send(nil, sub, "Yay! Web Push!", nil)
}

You can turn a JSON string representation of a PushSubscription object you collected from the browser into a Subscription struct with a helper function.

var exampleJSON = []byte(`{"endpoint": "...", "keys": {"p256dh": "...", "auth": "..."}}`)
sub, err := SubscriptionFromJSON(exampleJSON)

If the push service requires an authentication header (notably Google Cloud Messaging, used by Chrome) then you can add that as a fourth parameter:

if strings.Contains(sub.Endpoint, "https://android.googleapis.com/gcm/send/") {
  webpush.Send(nil, sub, "A message for Chrome", myGCMKey)
}

Index

Constants

View Source
const (
	WorkloadCertDir = "/var/run/secrets/workload-spiffe-credentials"

	// This is derived from CA certs plus all TrustAnchors.
	// In GKE, it is expected that Citadel roots will be configure using TrustConfig - so they are visible
	// to all workloads including TD proxyless GRPC.
	//
	// Outside of GKE, this is loaded from the mesh.env - the mesh gate is responsible to keep it up to date.
	WorkloadRootCAs = "ca_certificates.pem"
)
View Source
const UseMDSFullToken = true

Variables

View Source
var (
	// SecureTokenEndpoint is the Endpoint the STS client calls to.
	SecureTokenEndpoint = "https://sts.googleapis.com/v1/token"

	Scope = "https://www.googleapis.com/auth/cloud-platform"

	// Server side
	// TokenPath is url path for handling STS requests.
	TokenPath = "/token"
	// StsStatusPath is the path for dumping STS status.
	StsStatusPath = "/stsStatus"
	// URLEncodedForm is the encoding type specified in a STS request.
	URLEncodedForm = "application/x-www-form-urlencoded"
	// TokenExchangeGrantType is the required value for "grant_type" parameter in a STS request.
	TokenExchangeGrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
	// SubjectTokenType is the required token type in a STS request.
	SubjectTokenType = "urn:ietf:params:oauth:token-type:jwt"

	Debug = false
)

From nodeagent/plugin/providers/google/stsclient In Istio, the code is used if "GoogleCA" is set as CA_PROVIDER or CA_ADDR has the right prefix

View Source
var (
	MESH_NETWORK = []byte{0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0x00}
)

Functions

func ContextWithAuth

func ContextWithAuth(ctx context.Context, h2c *ReqContext) context.Context

func GetMDSIDToken

func GetMDSIDToken(ctx context.Context, aud string) (string, error)

Get an ID token from platform (GCP, etc)

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]" \
 -H "Metadata-Flavor: Google"

May fail and need retry

func GetPeerCertBytes

func GetPeerCertBytes(r *http.Request) []byte

http-related auth

func GetResponseCertBytes

func GetResponseCertBytes(r *http.Response) []byte

func GetSAN

func GetSAN(c *x509.Certificate) ([]string, error)

func GetToken

func GetToken(aud string) string

func IDFromCert

func IDFromCert(c []*x509.Certificate) string

func IDFromPublicKey

func IDFromPublicKey(key crypto.PublicKey) string

IDFromPublicKey returns a node ID based on the public key of the node - 52 bytes base32.

func IDFromPublicKeyBytes

func IDFromPublicKeyBytes(m []byte) string

func JwtRawParse

func JwtRawParse(tok string) (*JWTHead, *JWT, []byte, []byte, error)

func MDS

func MDS(w http.ResponseWriter, r *http.Request)

MDS emulates the GCP metadata server. MDS address is 169.254.169.254:80 - can be intercepted with iptables, or set using GCE_METADATA_HOST

gRPC library will use it if: - the env variable is set - a probe to the IP and URL / returns the proper flavor. - DNS resolves metadata.google.internal to the IP

func MarshalPrivateKey

func MarshalPrivateKey(key crypto.PrivateKey) []byte

func MarshalPublicKey

func MarshalPublicKey(key crypto.PublicKey) []byte

func MetadataGet

func MetadataGet(ctx context.Context, path string) (string, error)

GetMDS returns MDS info on google: instance/hostname - node name.c.PROJECT.internal instance/attributes/cluster-name, cluster-location project/project-id, numeric-project-id instance/service-accounts/ - default, PROJECTID.svc.id.goog instance/service-accounts/default/identity - requires the iam.gke.io/gcp-service-account=gsa@project annotation and IAM instance/service-accounts/default/token - access token for the KSA

func ParseAuthorization

func ParseAuthorization(auth string) (string, string, map[string]string)

ParseAuthorization splits the Authorization header, returning the scheme and parameters. Used with the "scheme k=v,k=v" format.

func ParseXFCC

func ParseXFCC(val string) map[string]string

ParseXFCC is a minimal (and probably buggy) parser for XFCC envoy header. It does not deal with quoted strings including special chars (,;=). Istio certs are safe.

func Pub2ID

func Pub2ID(pub []byte) uint64

Generate a 8-byte identifier from a public key

func Pub2VIP

func Pub2VIP(pub []byte) net.IP

Convert a public key to a VIP. This is the primary ID of the nodes. Primary format is the 64-byte EC256 public key.

For RSA, the ASN.1 format of the byte[] is used. For ED, the 32-byte raw encoding.

func PubKeyFromCertChain

func PubKeyFromCertChain(chain []*x509.Certificate) (crypto.PublicKey, error)

PubKeyFromCertChain verifies the certificate chain and extract the remote's public key.

func PublicKeyBytesRaw

func PublicKeyBytesRaw(key crypto.PublicKey) []byte

Convert a PublicKey to a marshalled format - in the raw format. - 32 byte ED25519 - 65 bytes EC256 ( 0x04 prefix ) - DER RSA key (PKCS1)

func RawToCertChain

func RawToCertChain(rawCerts [][]byte) ([]*x509.Certificate, error)

func TokenPayload

func TokenPayload(jwt string) string

TokenPayload returns the decoded token. Used for logging/debugging token content, without printing the signature.

func Verify

func Verify(data []byte, pub []byte, sig []byte) error

Types

type Auth

type Auth struct {
	// MeshAuth is minimal, simplified version of auth based only on platform certs.
	meshauth.MeshAuth

	// Public part of the Auth info
	//ugate.DMNode
	PublicKey []byte `json:"pub,omitempty"`
	ID        string `json:"id,omitempty"`

	// Primary VIP, Created from the PublicKey key, will be included in the self-signed cert.
	VIP6 net.IP

	// Same as VIP6, but as uint64
	VIP64 uint64

	// Blob store - for loading/saving certs and keys. If nil, all is just in memory.
	Config ConfStore

	// Moved to base
	// User name, based on service account or uid.
	Name string
	// Private key to use in both server and client authentication.
	// ED22519: 32B
	// EC256: DER
	// RSA: DER
	Priv []byte

	// Explicit certificates (lego), key is hostname from file
	//
	CertMap map[string]*tls.Certificate
	// contains filtered or unexported fields
}

Support for ID and authn using certificates and workload identity.

Private key, certificates and associated helpers. An IPv6 address is derived from the public key.

Auth represents a workload identity and associated info. It can load existing certificates from the well known location, and can save certificates to the well known locations.

When loading existing certificate it can extract namespace/trustdomain/sa.

func NewAuth

func NewAuth(cs ConfStore, name, domain string) *Auth

NewAuth initializes the auth using environment, local files or the config store.

If no private key is found, generate an EC256 key.

func NewMeshAuth

func NewMeshAuth() *Auth

func (*Auth) GenerateTLSConfigClient

func (auth *Auth) GenerateTLSConfigClient() *tls.Config

Generate a config to be used in a HTTP client, using the primary identity and cert.

func (*Auth) GetCerts

func (auth *Auth) GetCerts() map[string]*tls.Certificate

Get all known certificates from local files. This is used to support lego certificates and istio.

"istio" is a special name, set if istio certs are found

func (*Auth) HandleDisc

func (a *Auth) HandleDisc(w http.ResponseWriter, r *http.Request)

OIDC discovery on .well-known/openid-configuration

func (*Auth) HandleJWK

func (a *Auth) HandleJWK(w http.ResponseWriter, r *http.Request)

OIDC JWK

func (*Auth) Host2ID

func (auth *Auth) Host2ID(host string) string

Host2ID concerts a Host/:authority or path parameter hostname to a node ID.

func (*Auth) LoadManaged

func (a *Auth) LoadManaged()

func (*Auth) NewContextUA

func (a *Auth) NewContextUA(auth []byte) *EncryptionContext

func (*Auth) NodeID

func (auth *Auth) NodeID() []byte

func (*Auth) NodeIDUInt

func (auth *Auth) NodeIDUInt(pub []byte) uint64

func (*Auth) SaveKubeconfig

func (auth *Auth) SaveKubeconfig(name string, keyPEM []byte, certPEM []byte)

SaveKubeconfig will save the current keys and config as a kube config file.

func (*Auth) Self

func (a *Auth) Self() string

Return the self identity. Currently it's using the VIP6 format - may change. This is used in Message 'From' and in ReqContext.

func (*Auth) SetTLSCertificate

func (a *Auth) SetTLSCertificate(cert *tls.Certificate) error

import (

"context"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
"path/filepath"
"strings"
"time"

)

// This handles the ideal mesh case - platform managed workload certificates. // Also handles pilot-agent managing the certs.

// MeshAuth represents a workload identity and associated info required for minimal Mesh-compatible security.

type MeshAuth struct {
	// Will attempt to load certificates from this directory, defaults to
	// "./var/run/secrets/istio.io/"
	CertDir string

	// Current certificate, after calling GetCertificate("")
	Cert *tls.Certificate

	// MeshTLSConfig is a tls.Config that requires mTLS with a spiffee identity,
	// using the configured roots, trustdomains.
	//
	// By default only same namespace or istio-system are allowed - can be changed by
	// setting AllowedNamespaces. A "*" will allow all.
	MeshTLSConfig *tls.Config

	// TrustDomain is extracted from the cert or set by user, used to verify
	// peer certificates.
	TrustDomain string

	// Namespace and SA are extracted from the certificate or set by user.
	// Namespace is used to verify peer certificates
	Namespace string
	SA        string

	// Additional namespaces to allow access from. By default 'same namespace' and 'istio-system' are allowed.
	AllowedNamespaces []string

	// Trusted roots
	// TODO: copy Istiod multiple trust domains code. This will be a map[trustDomain]roots and a
	// list of TrustDomains. XDS will return the info via ProxyConfig.
	// This can also be done by krun - loading a config map with same info.
	TrustedCertPool *x509.CertPool

	// GetCertificateHook allows plugging in an alternative certificate provider. By default files are used.
	GetCertificateHook func(host string) (*tls.Certificate, error)
}
func (a *MeshAuth) GenerateTLSConfigServer() *tls.Config {
	return a.MeshTLSConfig
}
func (a *MeshAuth) GenerateTLSConfigClient(name string) *tls.Config {
	return a.MeshTLSConfig.Clone()
}

// NewMeshAuth creates the auth object. No keys are set. // // Private key, roots, config must be initialized and loaded. Use NewAuth(...) for automated loading // from environment/filesystem.

func NewMeshAuth() *Auth {
	a := &Auth{
		TrustedCertPool: x509.NewCertPool(),
	}
	return a
}

// mesh certificates - new style const (

WorkloadCertDir = "/var/run/secrets/workload-spiffe-credentials"

// Different from typical Istio  and CertManager key.pem - we can check both
privateKey = "private_key.pem"

// Also different, we'll check all. CertManager uses cert.pem
cert = "certificates.pem"

// This is derived from CA certs plus all TrustAnchors.
// In GKE, it is expected that Citadel roots will be configure using TrustConfig - so they are visible
// to all workloads including TD proxyless GRPC.
//
// Outside of GKE, this is loaded from the mesh.env - the mesh gate is responsible to keep it up to date.
WorkloadRootCAs = "ca_certificates.pem"

)

// CSRSigner is the provider interface for signing certs, defined in Istio. // CSR is generated by Auth.

type CSRSigner interface {
	CSRSign(ctx context.Context, csrPEM []byte, certValidTTLInSec int64) ([]string, error)
	GetRootCertBundle() ([]string, error)
}

// Will load the credentials and create an Auth object. // // This uses pilot-agent or some other platform tool creating ./var/run/secrets/istio.io/{key,cert-chain}.pem // // // TODO: ./etc/certs support: krun should copy the files, for consistency (simper code for frameworks). // TODO: periodic reload

func (a *Auth) SetKeysDir(dir string) error {
	a.CertDir = dir
	err := a.waitAndInitFromDir()
	if err != nil {
		return err
	}
	return nil
}
func (a *Auth) SetKeysPEM(privatePEM []byte, chainPEM []string) error {
	chainPEMCat := strings.Join(chainPEM, "\n")
	tlsCert, err := tls.X509KeyPair([]byte(chainPEMCat), privatePEM)
	if err != nil {
		return err
	}
	if tlsCert.Certificate == nil || len(tlsCert.Certificate) == 0 {
		return errors.New("missing certificate")
	}

	return a.SetTLSCertificate(&tlsCert)
}

func (*Auth) SetVapid

func (v *Auth) SetVapid(publicKey64, privateKey64 string)

SetVapid sets a new Vapid generator from EC256 public and private keys, in base64 uncompressed format.

func (*Auth) Sign

func (auth *Auth) Sign(data []byte, sig []byte)

Sign - requires ECDSA primary key

func (*Auth) SignCSR

func (auth *Auth) SignCSR(csrBytes []byte, org string, sans ...string) ([]byte, error)

func (*Auth) SignCert

func (auth *Auth) SignCert(priv crypto.PrivateKey, ca crypto.PrivateKey, sans ...string) (tls.Certificate, []byte, []byte)

func (*Auth) Spiffee

func (a *Auth) Spiffee() (*url.URL, string, string, string)

// GetCertificate is typically called during handshake, both server and client. // "sni" will be empty for client certificates, and set for server certificates - if not set, workload id is returned. // // ctx is the handshake context - may include additional metadata about the operation.

func (a *Auth) GetCertificate(ctx context.Context, sni string) (*tls.Certificate, error) {
	// TODO: if host != "", allow returning DNS certs for the host.
	// Default (and currently only impl) is to return the spiffe cert
	// May refresh.
	c, ok := a.CertMap[sni]
	if ok {
		return c, nil
	}

	// Have cert, not expired
	if a.Cert != nil {
		if !a.leaf().NotAfter.Before(time.Now()) {
			return a.Cert, nil
		}
	}

	if a.CertDir != "" {
		c, err := a.loadCertFromDir(a.CertDir)
		if err == nil {
			if !c.Leaf.NotAfter.Before(time.Now()) {
				a.Cert = c
			}
		} else {
			log.Println("Cert from dir failed", err)
		}
	}

	if a.GetCertificateHook != nil {
		c, err := a.GetCertificateHook(sni)
		if err != nil {
			return nil, err
		}
		a.Cert = c
	}

	return a.Cert, nil
}
func (a *Auth) loadCertFromDir(dir string) (*tls.Certificate, error) {
	// Load cert from file
	keyFile := filepath.Join(dir, "key.pem")
	keyBytes, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}
	certBytes, err := ioutil.ReadFile(filepath.Join(dir, "cert-chain.pem"))
	if err != nil {
		return nil, err
	}

	tlsCert, err := tls.X509KeyPair(certBytes, keyBytes)
	if err != nil {
		return nil, err
	}
	if tlsCert.Certificate == nil || len(tlsCert.Certificate) == 0 {
		return nil, errors.New("missing certificate")
	}
	tlsCert.Leaf, _ = x509.ParseCertificate(tlsCert.Certificate[0])

	return &tlsCert, nil
}
func (a *Auth) waitAndInitFromDir() error {
	if a.CertDir == "" {
		a.CertDir = "./var/run/secrets/istio.io/"
	}
	keyFile := filepath.Join(a.CertDir, "key.pem")
	err := waitFile(keyFile, 5*time.Second)
	if err != nil {
		return err
	}

	err = a.initFromDir()
	if err != nil {
		return err
	}

	time.AfterFunc(30*time.Minute, a.initFromDirPeriodic)
	return nil
}
func (a *Auth) initFromDirPeriodic() {
	err := a.initFromDir()
	if err != nil {
		log.Println("certRefresh", err)
	}
	time.AfterFunc(30*time.Minute, a.initFromDirPeriodic)
}

func (a *Auth) initFromDir() error {

	if a.Cert == nil {
		_, err := a.GetCertificate(context.Background(), "")
		if err != nil {
			return err
		}
	}

	rootCert, _ := ioutil.ReadFile(filepath.Join(a.CertDir, "root-cert.pem"))
	if rootCert != nil {
		err2 := a.AddRoots(rootCert)
		if err2 != nil {
			return err2
		}
	}

	istioCert, _ := ioutil.ReadFile("./var/run/secrets/istio/root-cert.pem")
	if istioCert != nil {
		err2 := a.AddRoots(istioCert)
		if err2 != nil {
			return err2
		}
	}

	// Similar with /etc/ssl/certs/ca-certificates.crt - the concatenated list of PEM certs.
	rootCertExtra, _ := ioutil.ReadFile(filepath.Join(a.CertDir, "ca-certificates.crt"))
	if rootCertExtra != nil {
		err2 := a.AddRoots(rootCertExtra)
		if err2 != nil {
			return err2
		}
	}
	// If the certificate has a chain, use the last cert - similar with Istio
	if len(a.Cert.Certificate) > 1 {
		last := a.Cert.Certificate[len(a.Cert.Certificate)-1]

		rootCAs, err := x509.ParseCertificates(last)
		if err == nil {
			for _, c := range rootCAs {
				log.Println("Adding root CA from cert chain: ", c.Subject)
				a.TrustedCertPool.AddCert(c)
			}
		}
	}

	a.initTLS()
	return nil
}

// InitRoots will find the mesh roots. // // - if Zatar or another CSI provider are enabled, we do nothing - Zatar config is the root of trust for everything // - otherwise the roots are expected to be part of mesh-env. The mesh connector or other tools will // populate it - ideally from the CSI/Zatar or TrustConfig CRD.

func (kr *Auth) InitRoots(ctx context.Context, outDir string) error {
	if outDir != "" {
		rootFile := filepath.Join(outDir, WorkloadRootCAs)
		rootCertPEM, err := ioutil.ReadFile(rootFile)
		if err == nil {
			block, rest := pem.Decode(rootCertPEM)

			var blockBytes []byte
			for block != nil {
				blockBytes = append(blockBytes, block.Bytes...)
				block, rest = pem.Decode(rest)
			}

			rootCAs, err := x509.ParseCertificates(blockBytes)
			if err != nil {
				return err
			}
			for _, c := range rootCAs {
				kr.TrustedCertPool.AddCert(c)
			}
			return nil
		}
	}

	// File not found - extract it from mesh env, and save it.
	// This includes Citadel root (if active in the mesh) or other roots.
	roots := ""
	block, rest := pem.Decode([]byte(roots))
	var blockBytes []byte
	for block != nil {
		blockBytes = append(blockBytes, block.Bytes...)
		block, rest = pem.Decode(rest)
	}

	rootCAs, err := x509.ParseCertificates(blockBytes)
	if err != nil {
		return err
	}
	for _, c := range rootCAs {
		kr.TrustedCertPool.AddCert(c)
	}

	return nil
}

// TODO: save last cert in the chain to roots

// Common setup for cert management. // After the 'mesh-env' is loaded (from env, k8s, URL) the next step is to init the workload identity. // This must happen before connecting to XDS - since certs is one of the possible auth methods. // // The logic is: // - (best case) certificates already provisioned by platform. Detects GKE paths (CAS), old Istio, CertManager style // If workload certs are platform-provisioned: extract trust domain, namespace, name, pod id from cert. // // - Detect the WORKLOAD_SERVICE_ACCOUNT, trust domain from JWT or mesh-env // - Use WORKLOAD_CERT json to load the config for the CSR, create a CSR // - Call CSRSigner. // - Save the certificates if running as root or an output dir is set. This will use CAS naming convention. // // If envoy + pilot-agent are used, they should be configured to use the cert files. // This is done by setting "CA_PROVIDER=GoogleGkeWorkloadCertificate" when starting pilot-agent

func (kr *Auth) InitCertificates(ctx context.Context, certDir string) error {
	if certDir == "" {
		certDir = WorkloadCertDir
	}
	var err error
	keyFile := filepath.Join(certDir, privateKey)
	chainFile := filepath.Join(certDir, cert)
	kr.privPEM, err = ioutil.ReadFile(keyFile)
	kr.certPEM, err = ioutil.ReadFile(chainFile)

	kp, err := tls.X509KeyPair(kr.certPEM, kr.privPEM)
	if err == nil && len(kp.Certificate) > 0 {
		kr.CertDir = certDir

		kp.Leaf, _ = x509.ParseCertificate(kp.Certificate[0])

		exp := kp.Leaf.NotAfter.Sub(time.Now())
		if exp > -5*time.Minute {
			kr.Cert = &kp
			log.Println("Existing Cert", "expires", exp)
			return nil
		}
	}
	return nil
}

Extract the trustDomain, namespace and Name from a spiffee certificate

func (*Auth) VAPIDToken

func (auth *Auth) VAPIDToken(aud string) string

VAPIDToken creates a token with the specified endpoint, using configured Sub id and a default expiration (1h).

Format is "vapid t=TOKEN k=PUBKEY

The optional (unauthenticated) Sub field is populated from Name@Domain or TrustDomain. The DMesh VIP is based on the public key of the signer. AUD is the URL from the subscription - for DMesh https://VIP:5228/s or https://DOMAIN:5228/s

type AuthConfig

type AuthConfig struct {
	// ProjectNumber is required - this code doesn't look it up.
	// Set as x-goog-user-project
	ProjectNumber string

	// TrustDomain to use - typically based on project name.
	TrustDomain string

	// GKE Cluster address.
	// https://container.googleapis.com/v1/projects/%s/locations/%s/clusters/%s
	// It is also the iss field in the token.
	ClusterAddress string

	// TokenSource returns K8S or federated tokens with a given audience.
	TokenSource TokenSource
}

AuthConfig contains the settings for getting tokens using K8S or federated tokens.

type ConfStore

type ConfStore interface {
	// Get a config blob by name
	Get(name string) ([]byte, error)

	// Save a config blob
	Set(conf string, data []byte) error

	// List the configs starting with a prefix, of a given type
	List(name string, tp string) ([]string, error)
}

Interface for very simple configuration and key loading. Can have a simple in-memory, fs implementation, as well as K8S, XDS or database backends.

The name is hierachical, in case of K8S or Istio corresponds to the type, including namespace.

type Context

type Context struct {
	// Cluster is the name of the cluster for this context
	Cluster string `json:"cluster"`
	// AuthInfo is the name of the authInfo for this context
	User string `json:"user"`
	// Namespace is the default namespace to use on unspecified requests
	// +optional
	Namespace string `json:"namespace,omitempty"`
}

Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster), a user (how do I identify myself), and a namespace (what subset of resources do I want to work with)

type Duration

type Duration struct {
	// Signed seconds of the span of time. Must be from -315,576,000,000
	// to +315,576,000,000 inclusive. Note: these bounds are computed from:
	// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
	Seconds int64 `json:"seconds"`
}

From tokenexchangeplugin.go

type EncryptionContext

type EncryptionContext struct {
	// Full body of the encrypted message, including header (salt, server pub)
	// Format:
	// 16 B Salt
	// 4B rs {0,0, 16, 0} - 4k
	// 1B ID-Size {65}
	// 65B SendPublicKey
	// Up to 4k encrypted text - with 0x02 appended at the end before encryption
	// Wasted: 7 const.
	// Overhead: 16 salt, 16 sig, 64 pub. Total: 103 (64+32+7)
	Ciphertext []byte

	// 16B For encryption: must be a random generated by sender.
	Salt []byte

	// Temp EC key for encryption, 65B
	SendPublic []byte

	// UA Public bytes - from subscription
	UAPublic []byte

	// Only used for encrypt
	SendPrivate []byte
	// Only used for decrypt
	UAPrivate []byte

	// Auth - from subscription
	Auth []byte
	// contains filtered or unexported fields
}

EncryptionContext stores the source and result of encrypting a message. The ciphertext is the actual encrypted message, while the salt and server public key are required to be sent to the client so that the message can be decrypted.

func NewContextSend

func NewContextSend(uapub, auth []byte) *EncryptionContext

func NewContextUA

func NewContextUA(uapriv, uapub, auth []byte) *EncryptionContext

Deprecated, test only

func (*EncryptionContext) Decrypt

func (er *EncryptionContext) Decrypt(cypher []byte) ([]byte, error)

func (*EncryptionContext) Encrypt

func (er *EncryptionContext) Encrypt(plaintext []byte) ([]byte, error)

Encrypt a message such that it can be sent using the Web Push protocol.

RFC8030 - message RFC8291 - encryption

type JWT

type JWT struct {
	//An "aud" (Audience) claim in the token MUST include the Unicode
	//serialization of the origin (Section 6.1 of [RFC6454]) of the push
	//resource URL.  This binds the token to a specific push service and
	//ensures that the token is reusable for all push resource URLs that
	//share the same origin.
	// In K8S it is an array !
	Aud MultiString `json:"aud,omitempty"`

	//If the application server wishes to provide contact details, it MAY
	//include a "sub" (Subject) claim in the JWT.  The "sub" claim SHOULD
	//include a contact URI for the application server as either a
	//"mailto:" (email) [RFC6068] or an "https:" [RFC2818] URI.
	Sub string `json:"sub,omitempty"`

	// Max 24h
	Exp int64 `json:"exp,omitempty"`
	IAT int64 `json:"iat,omitempty"`

	// Issuer - for example kubernetes/serviceaccount.
	Iss string `json:"iss,omitempty"`

	Email string `json:"email,omitempty"`

	EmailVerified bool `json:"email_verified,omitempty"`

	K8S K8SAccountInfo `json:"kubernetes.io"`

	Name string `json:"kubernetes.io/serviceaccount/service-account.name"`

	Raw string `json:-`
}

JWT includes minimal field for a JWT, primarily for extracting iss for the exchange. This is used with K8S JWTs, which use multi-string.

func CheckVAPID

func CheckVAPID(tok string, now time.Time) (jwt *JWT, pub []byte, err error)

CheckVAPID verifies the signature and returns the token and public key. expCheck should be set to current time to set expiration

Data is extracted from VAPID header - 'vapid' scheme and t/k params

Does not check audience or other parms.

type JWTHead

type JWTHead struct {
	Typ string `json:"typ"`
	Alg string `json:"alg,omitempty"`
}

type JWTRule

type JWTRule struct {

	// Example: https://foobar.auth0.com
	// Example: 1234567-compute@developer.gserviceaccount.com
	Issuer string `protobuf:"bytes,1,opt,name=issuer,proto3" json:"issuer,omitempty"`

	// The list of JWT
	// [audiences](https://tools.ietf.org/html/rfc7519#section-4.1.3).
	// that are allowed to access. A JWT containing any of these
	// audiences will be accepted.
	//
	// The service name will be accepted if audiences is empty.
	//
	// Example:
	//
	// “`yaml
	// audiences:
	// - bookstore_android.apps.example.com
	//   bookstore_web.apps.example.com
	// “`
	Audiences []string `protobuf:"bytes,2,rep,name=audiences,proto3" json:"audiences,omitempty"`

	// URL of the provider's public key set to validate signature of the
	// JWT. See [OpenID Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata).
	//
	// Optional if the key set document can either (a) be retrieved from
	// [OpenID
	// Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) of
	// the issuer or (b) inferred from the email domain of the issuer (e.g. a
	// Google service account).
	//
	// Example: `https://www.googleapis.com/oauth2/v1/certs`
	//
	// Note: Only one of jwks_uri and jwks should be used. jwks_uri will be ignored if it does.
	JwksUri string `protobuf:"bytes,3,opt,name=jwks_uri,json=jwksUri,proto3" json:"jwks_uri,omitempty"`
}

JWTRule - from istio API, as json.

type K8SAccountInfo

type K8SAccountInfo struct {
	Namespace string `json:"namespace"`
}

type KubeCluster

type KubeCluster struct {
	// LocationOfOrigin indicates where this object came from.  It is used for round tripping config post-merge, but never serialized.
	// +k8s:conversion-gen=false
	//LocationOfOrigin string
	// Server is the address of the kubernetes cluster (https://hostname:port).
	Server string `json:"server"`
	// InsecureSkipTLSVerify skips the validity check for the server's certificate. This will make your HTTPS connections insecure.
	// +optional
	InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"`
	// CertificateAuthority is the path to a cert file for the certificate authority.
	// +optional
	CertificateAuthority string `json:"certificate-authority,omitempty" yaml:"certificate-authority"`
	// CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority
	// +optional
	CertificateAuthorityData string `json:"certificate-authority-data,omitempty"  yaml:"certificate-authority-data"`
}

type KubeConfig

type KubeConfig struct {
	// Must be v1
	ApiVersion string `json:"apiVersion"`
	// Must be Config
	Kind string `json:"kind"`

	// Clusters is a map of referencable names to cluster configs
	Clusters []KubeNamedCluster `json:"clusters"`

	// AuthInfos is a map of referencable names to user configs
	Users []KubeNamedUser `json:"users"`

	// Contexts is a map of referencable names to context configs
	Contexts []KubeNamedContext `json:"contexts"`

	// CurrentContext is the name of the context that you would like to use by default
	CurrentContext string `json:"current-context" yaml:"current-context"`
}

KubeConfig is the JSON representation of the kube config. The format supports most of the things we need and also allows connection to real k8s clusters. UGate implements a very light subset - should be sufficient to connect to K8S, but without any generated stubs. Based in part on https://github.com/ericchiang/k8s (abandoned), which is a light client.

type KubeNamedCluster

type KubeNamedCluster struct {
	Name    string      `json:"name"`
	Cluster KubeCluster `json:"cluster"`
}

type KubeNamedContext

type KubeNamedContext struct {
	Name    string  `json:"name"`
	Context Context `json:"context"`
}

type KubeNamedUser

type KubeNamedUser struct {
	Name string   `json:"name"`
	User KubeUser `json:"user"`
}

type KubeUser

type KubeUser struct {
	// LocationOfOrigin indicates where this object came from.  It is used for round tripping config post-merge, but never serialized.
	// +k8s:conversion-gen=false
	//LocationOfOrigin string
	// ClientCertificate is the path to a client cert file for TLS.
	// +optional
	ClientCertificate string `json:"client-certificate,omitempty"`
	// ClientCertificateData contains PEM-encoded data from a client cert file for TLS. Overrides ClientCertificate
	// +optional
	ClientCertificateData []byte `json:"client-certificate-data,omitempty"`
	// ClientKey is the path to a client key file for TLS.
	// +optional
	ClientKey string `json:"client-key,omitempty"`
	// ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey
	// +optional
	ClientKeyData []byte `json:"client-key-data,omitempty"`
	// Token is the bearer token for authentication to the kubernetes cluster.
	// +optional
	Token string `json:"token,omitempty"`
	// TokenFile is a pointer to a file that contains a bearer token (as described above).  If both Token and TokenFile are present, Token takes precedence.
	// +optional
	TokenFile string `json:"tokenFile,omitempty"`
	// Impersonate is the username to act-as.
	// +optional
	//Impersonate string `json:"act-as,omitempty"`
	// ImpersonateGroups is the groups to imperonate.
	// +optional
	//ImpersonateGroups []string `json:"act-as-groups,omitempty"`
	// ImpersonateUserExtra contains additional information for impersonated user.
	// +optional
	//ImpersonateUserExtra map[string][]string `json:"act-as-user-extra,omitempty"`
	// Username is the username for basic authentication to the kubernetes cluster.
	// +optional
	Username string `json:"username,omitempty"`
	// Password is the password for basic authentication to the kubernetes cluster.
	// +optional
	Password string `json:"password,omitempty"`
	// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
	// +optional
	AuthProvider UserAuthProvider `json:"auth-provider,omitempty" yaml:"auth-provider,omitempty"`
}

KubeUser contains information that describes identity information. This is use to tell the kubernetes cluster who you are.

type MultiString

type MultiString []string

func (*MultiString) MarshalJSON

func (ms *MultiString) MarshalJSON() ([]byte, error)

func (*MultiString) UnmarshalJSON

func (ms *MultiString) UnmarshalJSON(data []byte) error

type RemoteID

type RemoteID struct {
	TrustDomain    string
	Namespace      string
	ServiceAccount string
}

func RemoteIDmTLS

func RemoteIDmTLS(xfcc string) *RemoteID

type ReqContext

type ReqContext struct {
	// Auth role - set if a authorized_keys or other authz is configured
	Role string

	// SAN list from the certificate, or equivalent auth method.
	SAN []string

	// Request start time
	T0 time.Time

	// Public key of the first cert in the chain (similar with SSH)
	Pub []byte

	// VIP associated with the public key.
	VIP net.IP

	VAPID *JWT
}

func AuthContext

func AuthContext(ctx context.Context) *ReqContext

func (*ReqContext) ID

func (rc *ReqContext) ID() string

ID of the caller, validated based on certs. Currently based on VIP6 for mesh nods.

type STS

type STS struct {

	// Google service account to impersonate and return tokens for.
	// The KSA returned from K8S must have the IAM permissions
	GSA string

	AudOverride string

	// K8S returns a token signed by k8s, no further exchanges.
	K8S bool

	// UseSTSExchange will return a token for an external service account.
	UseSTSExchange bool

	// UseAccessToken will force returning a GSA access token, regardless of audience.
	UseAccessToken bool
	// contains filtered or unexported fields
}

STS provides token exchanges. Implements grpc and golang.org/x/oauth2.TokenSource The source of trust is the K8S token with TrustDomain audience, it is exchanged with access or ID tokens.

func NewFederatedTokenSource

func NewFederatedTokenSource(kr *AuthConfig) *STS

NewFederatedTokenSource returns federated tokens - google access tokens associated with the federated (k8s) identity. Can be used in some but not all APIs - in particular MeshCA requires this token.

func NewGSATokenSource

func NewGSATokenSource(kr *AuthConfig, gsa string) *STS

NewGSATokenSource returns a oauth2.TokenSource and grpc credentials.PerRPCCredentials implmentation, returning access tokens for a Google Service Account.

If the gsa is empty, the ASM mesh P4SA will be used instead. This is suitable for connecting to stackdriver and out-of-cluster managed Istiod. Otherwise, the gsa must grant the KSA (kubernetes service account) permission to act as the GSA.

func NewK8STokenSource

func NewK8STokenSource(kr *AuthConfig, audOverride string) *STS

NewK8STokenSource returns a oauth2 and grpc token source that returns K8S signed JWTs with the given audience.

func NewSTS

func NewSTS(kr *AuthConfig) (*STS, error)

func (*STS) ExternalSA

func (s *STS) ExternalSA() string

func (*STS) GetRequestMetadata

func (s *STS) GetRequestMetadata(ctx context.Context, aud ...string) (map[string]string, error)

GetRequestMetadata implements credentials.PerRPCCredentials This can be used for both ID tokens or access tokens - if the 'aud' containts googleapis.com, access tokens are returned.

func (*STS) GetToken

func (s *STS) GetToken(ctx context.Context, aud string) (string, error)

func (*STS) RequireTransportSecurity

func (s *STS) RequireTransportSecurity() bool

func (*STS) ServeStsRequests

func (s *STS) ServeStsRequests(w http.ResponseWriter, req *http.Request)

ServeStsRequests handles STS requests and sends exchanged token in responses.

func (*STS) TokenAccess

func (s *STS) TokenAccess(ctx context.Context, federatedToken string, audience string) (string, error)

Exchange a federated token equivalent with the k8s JWT with the ASM p4SA. TODO: can be used with any GSA, if the permission to call generateAccessToken is granted. This is a good way to get access tokens for a GSA using the KSA, similar with TokenRequest in the other direction.

May return an ID token with aud or access token.

func (*STS) TokenFederated

func (s *STS) TokenFederated(ctx context.Context, k8sSAjwt string) (string, error)

TokenFederated exchanges the K8S JWT with a federated token (formerly called ExchangeToken)

type StsErrorResponse

type StsErrorResponse struct {
	// REQUIRED. A single ASCII Error code.
	Error string `json:"error"`
	// OPTIONAL. Human-readable ASCII [USASCII] text providing additional information.
	ErrorDescription string `json:"error_description"`
	// OPTIONAL. A URI identifying a human-readable web page with information
	// about the Error.
	ErrorURI string `json:"error_uri"`
}

StsErrorResponse stores all Error parameters sent as JSON in a STS Error response. The Error parameters are defined in https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16#section-2.2.2.

type StsRequestParameters

type StsRequestParameters struct {
	// REQUIRED. The value "urn:ietf:params:oauth:grant-type:token- exchange"
	// indicates that a token exchange is being performed.
	GrantType string
	// OPTIONAL. Indicates the location of the target service or resource where
	// the client intends to use the requested security token.
	Resource string
	// OPTIONAL. The logical name of the target service where the client intends
	// to use the requested security token.
	Audience string
	// OPTIONAL. A list of space-delimited, case-sensitive strings, that allow
	// the client to specify the desired Scope of the requested security token in the
	// context of the service or Resource where the token will be used.
	Scope string
	// OPTIONAL. An identifier, for the type of the requested security token.
	RequestedTokenType string
	// REQUIRED. A security token that represents the identity of the party on
	// behalf of whom the request is being made.
	SubjectToken string
	// REQUIRED. An identifier, that indicates the type of the security token in
	// the "subject_token" parameter.
	SubjectTokenType string
	// OPTIONAL. A security token that represents the identity of the acting party.
	ActorToken string
	// An identifier, that indicates the type of the security token in the
	// "actor_token" parameter.
	ActorTokenType string
}

StsRequestParameters stores all STS request attributes defined in https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16#section-2.1

type StsResponseParameters

type StsResponseParameters struct {
	// REQUIRED. The security token issued by the authorization server
	// in response to the token exchange request.
	AccessToken string `json:"access_token"`
	// REQUIRED. An identifier, representation of the issued security token.
	IssuedTokenType string `json:"issued_token_type"`
	// REQUIRED. A case-insensitive value specifying the method of using the access
	// token issued. It provides the client with information about how to utilize the
	// access token to access protected resources.
	TokenType string `json:"token_type"`
	// RECOMMENDED. The validity lifetime, in seconds, of the token issued by the
	// authorization server.
	ExpiresIn int64 `json:"expires_in"`
	// OPTIONAL, if the Scope of the issued security token is identical to the
	// Scope requested by the client; otherwise, REQUIRED.
	Scope string `json:"scope"`
	// OPTIONAL. A refresh token will typically not be issued when the exchange is
	// of one temporary credential (the subject_token) for a different temporary
	// credential (the issued token) for use in some other context.
	RefreshToken string `json:"refresh_token"`
}

StsResponseParameters stores all attributes sent as JSON in a successful STS response. These attributes are defined in https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16#section-2.2.1

type Subscription

type Subscription struct {
	// Endpoint is the URL to send the Web Push message to. Comes from the
	// endpoint field of the PushSubscription.
	Endpoint string

	// Key is the client's public key. From the getKey("p256dh") or keys.p256dh field.
	Key []byte

	// Auth is a value used by the client to validate the encryption. From the
	// keys.auth field.
	// The encrypted aes128gcm will have 16 bytes authentication tag derived from this.
	// This is the pre-shared authentication secret.
	Auth []byte

	// Used by the UA to receive messages, as PUSH promises
	Location string
}

Subscription holds the useful values from a PushSubscription object acquired from the browser.

https://w3c.github.io/push-api/

Returned as result of /subscribe

func SubscriptionFromJSON

func SubscriptionFromJSON(b []byte) (*Subscription, error)

SubscriptionFromJSON is a convenience function that takes a JSON encoded PushSubscription object acquired from the browser and returns a pointer to a node.

type TokenCache

type TokenCache struct {
	// contains filtered or unexported fields
}

func NewTokenCache

func NewTokenCache(sts *STS) *TokenCache

func (*TokenCache) Token

func (c *TokenCache) Token(ctx context.Context, host string) (string, error)

type TokenSource

type TokenSource interface {
	// GetToken for a given audience.
	GetToken(context.Context, string) (string, error)
}

type UserAuthProvider

type UserAuthProvider struct {
	Name string `json:"name,omitempty"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL