Documentation ¶
Index ¶
- Constants
- Variables
- func ClientIdentityAware(cip IdentityProvider, verifiers ...VerifyXFCC) web.Middleware
- func ClientIdentityRequired(cip IdentityProvider, verifiers ...VerifyXFCC) web.Middleware
- func ExtractAndVerifyClientIdentity(req *http.Request, cip IdentityProvider, verifiers ...VerifyXFCC) (string, error)
- func GetClientIdentity(ctx context.Context) string
- func IsExtractionError(err error) bool
- func IsFatalError(err error) bool
- func IsValidationError(err error) bool
- func MaybeWaitForAdmin(log logger.Log) error
- func WithClientIdentity(ctx context.Context, clientIdentity string) context.Context
- type HTTPGetClient
- type IdentityFormatter
- type IdentityProcessor
- func (ip IdentityProcessor) IdentityProvider(xfcc XFCCElement) (string, error)
- func (ip IdentityProcessor) KubernetesIdentityFormatter(xfcc XFCCElement, pu *spiffeutil.ParsedURI) (string, error)
- func (ip IdentityProcessor) ProcessAllowedIdentities(xfcc XFCCElement, identity string) error
- func (ip IdentityProcessor) ProcessAllowedTrustDomains(xfcc XFCCElement, pu *spiffeutil.ParsedURI) error
- func (ip IdentityProcessor) ProcessDeniedIdentities(xfcc XFCCElement, identity string) error
- func (ip IdentityProcessor) ProcessDeniedTrustDomains(xfcc XFCCElement, pu *spiffeutil.ParsedURI) error
- type IdentityProcessorOption
- func OptAllowedIdentities(identities ...string) IdentityProcessorOption
- func OptAllowedTrustDomains(trustDomains ...string) IdentityProcessorOption
- func OptDeniedIdentities(identities ...string) IdentityProcessorOption
- func OptDeniedTrustDomains(trustDomains ...string) IdentityProcessorOption
- func OptFormatIdentity(formatter IdentityFormatter) IdentityProcessorOption
- func OptIdentityType(it IdentityType) IdentityProcessorOption
- type IdentityProvider
- type IdentityType
- type VerifyXFCC
- type WaitForAdmin
- type XFCC
- type XFCCElement
- func (xe XFCCElement) DecodeBy() (*url.URL, error)
- func (xe XFCCElement) DecodeCert() (*x509.Certificate, error)
- func (xe XFCCElement) DecodeChain() ([]*x509.Certificate, error)
- func (xe XFCCElement) DecodeHash() ([]byte, error)
- func (xe XFCCElement) DecodeURI() (*url.URL, error)
- func (xe XFCCElement) String() string
- type XFCCExtractionError
- type XFCCFatalError
- type XFCCValidationError
Constants ¶
const ( // ErrMissingXFCC is the error returned when XFCC is missing. ErrMissingXFCC = ex.Class("Missing X-Forwarded-Client-Cert header") // ErrInvalidXFCC is the error returned when XFCC is invalid. ErrInvalidXFCC = ex.Class("Invalid X-Forwarded-Client-Cert header") // ErrInvalidClientIdentity is the error returned when XFCC has a // missing / invalid client identity. ErrInvalidClientIdentity = ex.Class("Client identity could not be determined from X-Forwarded-Client-Cert header") // ErrDeniedClientIdentity is the error returned when a parsed client identity is in a deny list or // not in an allow list. ErrDeniedClientIdentity = ex.Class("Client identity from X-Forwarded-Client-Cert header is denied") // ErrInvalidServerIdentity is the error returned when XFCC has a // missing / invalid client identity. ErrInvalidServerIdentity = ex.Class("Server identity could not be determined from X-Forwarded-Client-Cert header") // ErrDeniedServerIdentity is the error returned when a parsed client identity is in a deny list or // not in an allow list. ErrDeniedServerIdentity = ex.Class("Server identity from X-Forwarded-Client-Cert header is denied") // ErrMissingExtractFunction is the message used when the "extract client // identity" function is `nil` or not provided. ErrMissingExtractFunction = ex.Class("Missing client identity extraction function") // ErrVerifierNil is the message prefix used when a provided verifier is `nil`. ErrVerifierNil = ex.Class("XFCC verifier must not be `nil`") )
const ( // EnvVarWaitFlag is an environment variable which specifies whether // a wait function should wait for the Envoy Admin API to be ready. EnvVarWaitFlag = "WAIT_FOR_ENVOY" // EnvVarAdminPort is an environment variable which provides an override // for the Envoy Admin API port. EnvVarAdminPort = "ENVOY_ADMIN_PORT" // DefaultAdminPort is the default port used for the Envoy Admin API. DefaultAdminPort = "15000" // EnumStateLive is a `envoy.admin.v3.ServerInfo.State` value indicating // the Envoy server is LIVE. Other possible values of this enum are // DRAINING, PRE_INITIALIZING and INITIALIZING, but they are not used // here. // See: https://github.com/envoyproxy/envoy/blob/b867a4dfae32e600ea0a4087dc7925ded5e2ab2a/api/envoy/admin/v3/server_info.proto#L24-L36 EnumStateLive = "LIVE" )
const ( // ErrXFCCParsing is the class of error returned when parsing XFCC fails ErrXFCCParsing = ex.Class("Error Parsing X-Forwarded-Client-Cert") )
const (
// HeaderXFCC is the header key for forwarded client cert
HeaderXFCC = "x-forwarded-client-cert"
)
Variables ¶
var ( // ErrFailedAttempt is an error class returned when Envoy fails to be // ready on a single attempt. ErrFailedAttempt = ex.Class("Envoy not yet ready") // ErrTimedOut is an error class returned when Envoy fails to be ready // after exhausting all attempts. ErrTimedOut = ex.Class("Timed out waiting for Envoy to be ready") )
Functions ¶
func ClientIdentityAware ¶
func ClientIdentityAware(cip IdentityProvider, verifiers ...VerifyXFCC) web.Middleware
ClientIdentityAware produces a middleware function nearly identical to `ClientIdentityRequired`. The primary difference is that this middleware will **not** return an error HTTP response for extraction or validation errors; it will still return a 500 Internal Server Error in unexpected failures. In cases of extraction or validation errors, the middleware will pass along to the next `action` and the client identity is not set on the current context.
func ClientIdentityRequired ¶
func ClientIdentityRequired(cip IdentityProvider, verifiers ...VerifyXFCC) web.Middleware
ClientIdentityRequired produces a middleware function that determines the client identity used in a connection secured with mTLS.
This parses the `X-Forwarded-Client-Cert` (XFCC) from a request and uses a client identity provider (`cip`, e.g. see `SPIFFEClientIdentityProvider()`) to determine the client identity. Additionally, optional `verifiers` (e.g. see `SPIFFEServerIdentityProvider()`) can be used to verify other parts of the XFCC header such as the identity of the current server.
In cases of error, the client identity will not be set on the current context. For error status codes 400 and 401, the error will be serialized as JSON or XML (via `ctx.DefaultProvider`) and returned in the HTTP response. For error status code 500, no identifying information from the error will be returned in the HTTP response.
A 401 Unauthorized will be returned in the following cases:
- The XFCC header is missing
- The XFCC header (after parsing) contains zero elements or multiple elements (this code expects exactly one XFCC element, under the assumption that the Envoy `ForwardClientCertDetails` setting is configured to `SANITIZE_SET`)
- The values from the XFCC header fail custom validation provided by `cip` or `verifiers`. For example, if the client identity is contained in a deny list, this would be considered a validation error.
A 400 Bad Request will be returned in the following cases:
- The XFCC header cannot be parsed
- Custom parsing / extraction done by `cip` fails. For example, in cases where the `URI` field in the XFCC is expected to be a valid SPIFFE URI with a valid Kubernetes workload identifier, if the `URI` field does not follow that format (e.g. `urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66`) this would be considered an extraction error.
A 500 Internal Server Error will be returned if the error is unrelated to validating the XFCC header or to parsing / extracting values from the XFCC header.
func ExtractAndVerifyClientIdentity ¶
func ExtractAndVerifyClientIdentity(req *http.Request, cip IdentityProvider, verifiers ...VerifyXFCC) (string, error)
ExtractAndVerifyClientIdentity enables extracting client identity from a request. It does so by requiring the XFCC header to be present and valid and contain exactly one element. Then it passes the parsed XFCC header along to some `verifiers` (e.g. to verify the server identity) as well as to an extractor `cip` (for the client identity).
func GetClientIdentity ¶
GetClientIdentity returns the client identity of the calling service or `""` if the client identity is unset.
For example if `rc` is a `*web.Ctx` ``` envoyutil.GetClientIdentity(rc.Context()) ```
func IsExtractionError ¶
IsExtractionError is a helper to check if an error is an `*XFCCExtractionError`.
func IsFatalError ¶
IsFatalError is a helper to check if an error is an `*XFCCFatalError`.
func IsValidationError ¶
IsValidationError is a helper to check if an error is an `*XFCCValidationError`.
func MaybeWaitForAdmin ¶
MaybeWaitForAdmin will check if Envoy is running if the `WAIT_FOR_ENVOY` environment variable is set. This will communicate with the Envoy admin port running on `localhost`, which defaults to 15000 but can be overriden with `ENVOY_ADMIN_PORT`. It will send `GET /ready` up to 10 times, sleeping for 1 second in between if the response is not 200 OK with a body of `LIVE\n`.
Types ¶
type HTTPGetClient ¶
HTTPGetClient captures a small part of the `http.Client` interface needed to execute a GET request.
type IdentityFormatter ¶
type IdentityFormatter = func(XFCCElement, *spiffeutil.ParsedURI) (string, error)
IdentityFormatter describes functions that will produce an identity string from a parsed SPIFFE URI.
type IdentityProcessor ¶
type IdentityProcessor struct { Type IdentityType AllowedTrustDomains []string DeniedTrustDomains []string AllowedIdentities collections.SetOfString DeniedIdentities collections.SetOfString FormatIdentity IdentityFormatter }
IdentityProcessor provides configurable fields that can be used to help validate a parsed SPIFFE URI and produce and validate an identity from a parsed SPIFFE URI. The `Type` field determines if a client or server identity should be provided; by default the type will be client identity.
func (IdentityProcessor) IdentityProvider ¶
func (ip IdentityProcessor) IdentityProvider(xfcc XFCCElement) (string, error)
IdentityProvider returns a client or server identity; it uses the configured rules to validate and format the identity by parsing the `URI` field (for client identity) or `By` field (for server identity) of the XFCC element. If `FormatIdentity` has not been specified, the `KubernetesIdentityFormatter()` method will be used as a fallback.
This method satisfies the `IdentityProvider` interface.
func (IdentityProcessor) KubernetesIdentityFormatter ¶
func (ip IdentityProcessor) KubernetesIdentityFormatter(xfcc XFCCElement, pu *spiffeutil.ParsedURI) (string, error)
KubernetesIdentityFormatter assumes the SPIFFE URI contains a Kubernetes workload ID of the form `ns/{namespace}/sa/{serviceAccount}` and formats the identity as `{serviceAccount}.{namespace}`. This function satisfies the `IdentityFormatter` interface.
func (IdentityProcessor) ProcessAllowedIdentities ¶
func (ip IdentityProcessor) ProcessAllowedIdentities(xfcc XFCCElement, identity string) error
ProcessAllowedIdentities returns an error if an allow list is configured and the identity does not match any elements in the list.
func (IdentityProcessor) ProcessAllowedTrustDomains ¶
func (ip IdentityProcessor) ProcessAllowedTrustDomains(xfcc XFCCElement, pu *spiffeutil.ParsedURI) error
ProcessAllowedTrustDomains returns an error if an allow list is configured and the trust domain from the parsed SPIFFE URI does not match any elements in the list.
func (IdentityProcessor) ProcessDeniedIdentities ¶
func (ip IdentityProcessor) ProcessDeniedIdentities(xfcc XFCCElement, identity string) error
ProcessDeniedIdentities returns an error if a denied list is configured and the identity matches any elements in the list.
func (IdentityProcessor) ProcessDeniedTrustDomains ¶
func (ip IdentityProcessor) ProcessDeniedTrustDomains(xfcc XFCCElement, pu *spiffeutil.ParsedURI) error
ProcessDeniedTrustDomains returns an error if a denied list is configured and the trust domain from the parsed SPIFFE URI matches any elements in the list.
type IdentityProcessorOption ¶
type IdentityProcessorOption func(*IdentityProcessor)
IdentityProcessorOption mutates an identity processor.
func OptAllowedIdentities ¶
func OptAllowedIdentities(identities ...string) IdentityProcessorOption
OptAllowedIdentities adds allowed identities to the processor.
func OptAllowedTrustDomains ¶
func OptAllowedTrustDomains(trustDomains ...string) IdentityProcessorOption
OptAllowedTrustDomains adds allowed trust domains to the processor.
func OptDeniedIdentities ¶
func OptDeniedIdentities(identities ...string) IdentityProcessorOption
OptDeniedIdentities adds denied identities to the processor.
func OptDeniedTrustDomains ¶
func OptDeniedTrustDomains(trustDomains ...string) IdentityProcessorOption
OptDeniedTrustDomains adds denied trust domains to the processor.
func OptFormatIdentity ¶
func OptFormatIdentity(formatter IdentityFormatter) IdentityProcessorOption
OptFormatIdentity sets the `FormatIdentity` on the processor.
func OptIdentityType ¶
func OptIdentityType(it IdentityType) IdentityProcessorOption
OptIdentityType sets the identity type for the processor.
type IdentityProvider ¶
type IdentityProvider func(xfcc XFCCElement) (identity string, err error)
IdentityProvider is a function to extract the client or server identity from a parsed XFCC header. For example, client identity could be determined from the SPIFFE URI in the `URI` field in an XFCC element.
func SPIFFEClientIdentityProvider ¶
func SPIFFEClientIdentityProvider(opts ...IdentityProcessorOption) IdentityProvider
SPIFFEClientIdentityProvider produces a function satisfying `IdentityProvider`.
This function assumes the client identity is in the `URI` field and that field is a SPIFFE URI.
It delegates processing of that SPIFFE URI via the `IdentityProcessor` type. The options supported can
- Provide an allow list for the trust domain in the SPIFFE URI.
- Provide a deny list for the trust domain in the SPIFFE URI.
- Provide a function to produce a client identity string from the SPIFFE URI (likely from the workload ID in the SPIFFE URI); if no option is provided for this the default will use `IdentityProcessor.KubernetesIdentityFormatter`.
- Provide an allow list for the client identity string.
- Provide a deny list for the client identity string.
type IdentityType ¶
type IdentityType int
IdentityType represents the type of identity that will be extracted by an `IdentityProcessor`. It can either be a client or server identity.
const ( // ClientIdentity represents client identity. ClientIdentity IdentityType = 0 // ServerIdentity represents server identity. ServerIdentity IdentityType = 1 )
type VerifyXFCC ¶
type VerifyXFCC func(xfcc XFCCElement) error
VerifyXFCC is an "extra" verifier for an XFCC, for example if the server identity (from the `By` field in an XFCC element) should be verified in addition to the client identity.
func SPIFFEServerIdentityProvider ¶
func SPIFFEServerIdentityProvider(opts ...IdentityProcessorOption) VerifyXFCC
SPIFFEServerIdentityProvider produces a verifier function satisfying `VerifyXFCC`.
This function assumes the server identity is in the `By` field and that field is a SPIFFE URI.
It delegates processing of that SPIFFE URI via the `IdentityProcessor` type. The options supported can
- Provide an allow list for the trust domain in the SPIFFE URI.
- Provide a deny list for the trust domain in the SPIFFE URI.
- Provide a function to produce a server identity string from the SPIFFE URI (likely from the workload ID in the SPIFFE URI); if no option is provided for this the default will use `IdentityProcessor.KubernetesIdentityFormatter`.
- Provide an allow list for the server identity string.
- Provide a deny list for the server identity string.
type WaitForAdmin ¶
type WaitForAdmin struct { // Port is the port (on localhost) where the Envoy Admin API is running. Port string // Sleep is the amount of time to sleep in between failed liveness // checks for the Envoy API. Sleep time.Duration // HTTPClient is the HTTP client to use when sending requests. HTTPClient HTTPGetClient // Log is an optional logger to be used when executing. Log logger.Log // Attempt is a counter for the number of attempts that have been made // to `executeOnce()`. This makes no attempt at "resetting" or guarding // against concurrent usage or re-usage of a `WaitForAdmin` struct. Attempt uint32 }
WaitForAdmin encapsulates the settings needed to wait until the Envoy Admin API is ready.
func (*WaitForAdmin) Execute ¶
func (wfa *WaitForAdmin) Execute(ctx context.Context) error
Execute will communicate with the Envoy admin port running on `localhost`, which defaults to 15000 but can be overriden with `ENVOY_ADMIN_PORT`. It will send `GET /ready` up to 10 times, sleeping for `wfa.Sleep` in between if the response is not 200 OK with a body of `LIVE\n`.
func (*WaitForAdmin) IsReady ¶
func (wfa *WaitForAdmin) IsReady() bool
IsReady makes a single request to the Envoy Admin API and checks if the status is ready.
type XFCC ¶
type XFCC []XFCCElement
XFCC represents a proxy header containing certificate information for the client that is sending the request to the proxy. See https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-client-cert
type XFCCElement ¶
type XFCCElement struct { // By contains Subject Alternative Name (URI type) of the current proxy's // certificate. This can be decoded as a `*url.URL` via `xe.DecodeBy()`. By string // Hash contains the SHA 256 digest of the current client certificate; this // is a string of 64 hexadecimal characters. This can be converted to the raw // bytes underlying the hex string via `xe.DecodeHash()`. Hash string // Cert contains the entire client certificate in URL encoded PEM format. // This can be decoded as a `*x509.Certificate` via `xe.DecodeCert()`. Cert string // Chain contains entire client certificate chain (including the leaf certificate) // in URL encoded PEM format. This can be decoded as a `[]*x509.Certificate` via // `xe.DecodeChain()`. Chain string // Subject contains the `Subject` field of the current client certificate. Subject string // URI contains the URI SAN of the current client certificate (assumes only // one URI SAN). This can be decoded as a `*url.URL` via `xe.DecodeURI()`. URI string // DNS contains the DNS SANs of the current client certificate. A client // certificate may contain multiple DNS SANs, each will be a separate // key-value pair in the XFCC element. DNS []string }
XFCCElement is an element in an XFCC header (see `XFCC`).
func (XFCCElement) DecodeBy ¶
func (xe XFCCElement) DecodeBy() (*url.URL, error)
DecodeBy decodes the `By` element from a URI string to a `*url.URL`.
func (XFCCElement) DecodeCert ¶
func (xe XFCCElement) DecodeCert() (*x509.Certificate, error)
DecodeCert decodes the `Cert` element from a URL encoded PEM to a single `x509.Certificate`.
func (XFCCElement) DecodeChain ¶
func (xe XFCCElement) DecodeChain() ([]*x509.Certificate, error)
DecodeChain decodes the `Chain` element from a URL encoded PEM to a `[]x509.Certificate`.
func (XFCCElement) DecodeHash ¶
func (xe XFCCElement) DecodeHash() ([]byte, error)
DecodeHash decodes the `Hash` element from a hex string to raw bytes.
func (XFCCElement) DecodeURI ¶
func (xe XFCCElement) DecodeURI() (*url.URL, error)
DecodeURI decodes the `URI` element from a URI string to a `*url.URL`.
func (XFCCElement) String ¶
func (xe XFCCElement) String() string
String converts the parsed XFCC element **back** to a string. This is intended for debugging purposes and is not particularly
type XFCCExtractionError ¶
type XFCCExtractionError struct { // Class can be used to uniquely identify the type of the error. Class ex.Class `json:"class" xml:"class"` // XFCC contains the XFCC header value that could not be parsed or was // invalid in some way. XFCC string `json:"xfcc,omitempty" xml:"xfcc,omitempty"` // Metadata contains extra information relevant to a specific failure. Metadata interface{} `json:"metadata,omitempty" xml:"metadata,omitempty"` }
XFCCExtractionError contains metadata about an XFCC header that could not be parsed or extracted. This is intended to be used as the body of a 401 Unauthorized response.
func (*XFCCExtractionError) Error ¶
func (xee *XFCCExtractionError) Error() string
Error satisfies the `error` interface. It is intended to be a unique identifier for the error.
type XFCCFatalError ¶
type XFCCFatalError struct { // Class can be used to uniquely identify the type of the error. Class ex.Class `json:"class" xml:"class"` // XFCC contains the XFCC header value that could not be parsed or was // invalid in some way. XFCC string `json:"xfcc,omitempty" xml:"xfcc,omitempty"` }
XFCCFatalError contains metadata about an unrecoverable failure when parsing an XFCC header. A "fatal error" should indicate invalid usage of `envoyutil` such as providing a `nil` value for a function interface that must be invoked.
func (*XFCCFatalError) Error ¶
func (xfe *XFCCFatalError) Error() string
Error satisfies the `error` interface. It is intended to be a unique identifier for the error.
type XFCCValidationError ¶
type XFCCValidationError struct { // Class can be used to uniquely identify the type of the error. Class ex.Class `json:"class" xml:"class"` // XFCC contains the XFCC header value that could not be parsed or was // invalid in some way. XFCC string `json:"xfcc,omitempty" xml:"xfcc,omitempty"` // Metadata contains extra information relevant to a specific failure. Metadata interface{} `json:"metadata,omitempty" xml:"metadata,omitempty"` }
XFCCValidationError contains metadata about an XFCC header that could not be parsed or extracted. This is intended to be used as the body of a 401 Unauthorized response.
func (*XFCCValidationError) Error ¶
func (xve *XFCCValidationError) Error() string
Error satisfies the `error` interface. It is intended to be a unique identifier for the error.