github.com/blend/go-sdk@v1.20220411.3/envoyutil/identity.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package envoyutil
     9  
    10  import (
    11  	"net/http"
    12  
    13  	"github.com/blend/go-sdk/ex"
    14  )
    15  
    16  const (
    17  	// ErrMissingXFCC is the error returned when XFCC is missing.
    18  	ErrMissingXFCC = ex.Class("Missing X-Forwarded-Client-Cert header")
    19  	// ErrInvalidXFCC is the error returned when XFCC is invalid.
    20  	ErrInvalidXFCC = ex.Class("Invalid X-Forwarded-Client-Cert header")
    21  	// ErrInvalidClientIdentity is the error returned when XFCC has a
    22  	// missing / invalid client identity.
    23  	ErrInvalidClientIdentity = ex.Class("Client identity could not be determined from X-Forwarded-Client-Cert header")
    24  	// ErrDeniedClientIdentity is the error returned when a parsed client identity is in a deny list or
    25  	// not in an allow list.
    26  	ErrDeniedClientIdentity = ex.Class("Client identity from X-Forwarded-Client-Cert header is denied")
    27  	// ErrInvalidServerIdentity is the error returned when XFCC has a
    28  	// missing / invalid client identity.
    29  	ErrInvalidServerIdentity = ex.Class("Server identity could not be determined from X-Forwarded-Client-Cert header")
    30  	// ErrDeniedServerIdentity is the error returned when a parsed client identity is in a deny list or
    31  	// not in an allow list.
    32  	ErrDeniedServerIdentity = ex.Class("Server identity from X-Forwarded-Client-Cert header is denied")
    33  	// ErrMissingExtractFunction is the message used when the "extract client
    34  	// identity" function is `nil` or not provided.
    35  	ErrMissingExtractFunction = ex.Class("Missing client identity extraction function")
    36  	// ErrVerifierNil is the message prefix used when a provided verifier is `nil`.
    37  	ErrVerifierNil = ex.Class("XFCC verifier must not be `nil`")
    38  )
    39  
    40  // IdentityProvider is a function to extract the client or server identity from
    41  // a parsed XFCC header. For example, client identity could be determined from the
    42  // SPIFFE URI in the `URI` field in an XFCC element.
    43  type IdentityProvider func(xfcc XFCCElement) (identity string, err error)
    44  
    45  // VerifyXFCC is an "extra" verifier for an XFCC, for example if the server
    46  // identity (from the `By` field in an XFCC element) should be verified in
    47  // addition to the client identity.
    48  type VerifyXFCC func(xfcc XFCCElement) error
    49  
    50  // ExtractAndVerifyClientIdentity enables extracting client identity from a request.
    51  // It does so by requiring the XFCC header to be present and valid and contain exactly
    52  // one element. Then it passes the parsed XFCC header along to some `verifiers` (e.g.
    53  // to verify the server identity) as well as to an extractor `cip` (for the
    54  // client identity).
    55  func ExtractAndVerifyClientIdentity(req *http.Request, cip IdentityProvider, verifiers ...VerifyXFCC) (string, error) {
    56  	if cip == nil {
    57  		return "", &XFCCFatalError{Class: ErrMissingExtractFunction}
    58  	}
    59  
    60  	// Early exit if XFCC header is not present.
    61  	xfccValue := req.Header.Get(HeaderXFCC)
    62  	if xfccValue == "" {
    63  		return "", &XFCCValidationError{Class: ErrMissingXFCC}
    64  	}
    65  
    66  	// Early exit if XFCC header is invalid, or has zero or multiple elements.
    67  	xfccElements, parseErr := ParseXFCC(xfccValue)
    68  	if parseErr != nil {
    69  		return "", &XFCCExtractionError{Class: ErrInvalidXFCC, XFCC: xfccValue}
    70  	}
    71  	if len(xfccElements) != 1 {
    72  		return "", &XFCCValidationError{Class: ErrInvalidXFCC, XFCC: xfccValue}
    73  	}
    74  	xfcc := xfccElements[0]
    75  
    76  	// Run all verifiers on the parsed `xfcc`.
    77  	for _, verifier := range verifiers {
    78  		if verifier == nil {
    79  			return "", &XFCCFatalError{Class: ErrVerifierNil, XFCC: xfccValue}
    80  		}
    81  
    82  		err := verifier(xfcc)
    83  		if err != nil {
    84  			return "", err
    85  		}
    86  	}
    87  
    88  	// Do final extraction.
    89  	return cip(xfcc)
    90  }
    91  
    92  // SPIFFEClientIdentityProvider produces a function satisfying `IdentityProvider`.
    93  //
    94  // This function assumes the client identity is in the `URI` field and that field
    95  // is a SPIFFE URI.
    96  //
    97  // It delegates processing of that SPIFFE URI via the `IdentityProcessor`
    98  // type. The options supported can
    99  // - Provide an allow list for the trust domain in the SPIFFE URI.
   100  // - Provide a deny list for the trust domain in the SPIFFE URI.
   101  // - Provide a function to produce a client identity string from the SPIFFE
   102  //   URI (likely from the workload ID in the SPIFFE URI); if no option is
   103  //   provided for this the default will use
   104  //   `IdentityProcessor.KubernetesIdentityFormatter`.
   105  // - Provide an allow list for the client identity string.
   106  // - Provide a deny list for the client identity string.
   107  func SPIFFEClientIdentityProvider(opts ...IdentityProcessorOption) IdentityProvider {
   108  	processor := IdentityProcessor{}
   109  	for _, opt := range opts {
   110  		opt(&processor)
   111  	}
   112  	// Ensure the `Type` is "client" even if `opts` set it to be otherwise.
   113  	processor.Type = ClientIdentity
   114  	return processor.IdentityProvider
   115  }
   116  
   117  // SPIFFEServerIdentityProvider produces a verifier function satisfying `VerifyXFCC`.
   118  //
   119  // This function assumes the server identity is in the `By` field and that field
   120  // is a SPIFFE URI.
   121  //
   122  // It delegates processing of that SPIFFE URI via the `IdentityProcessor`
   123  // type. The options supported can
   124  // - Provide an allow list for the trust domain in the SPIFFE URI.
   125  // - Provide a deny list for the trust domain in the SPIFFE URI.
   126  // - Provide a function to produce a server identity string from the SPIFFE
   127  //   URI (likely from the workload ID in the SPIFFE URI); if no option is
   128  //   provided for this the default will use
   129  //   `IdentityProcessor.KubernetesIdentityFormatter`.
   130  // - Provide an allow list for the server identity string.
   131  // - Provide a deny list for the server identity string.
   132  func SPIFFEServerIdentityProvider(opts ...IdentityProcessorOption) VerifyXFCC {
   133  	processor := IdentityProcessor{}
   134  	for _, opt := range opts {
   135  		opt(&processor)
   136  	}
   137  	// Ensure the `Type` is "server" even if `opts` set it to be otherwise.
   138  	processor.Type = ServerIdentity
   139  
   140  	return func(xfcc XFCCElement) error {
   141  		_, err := processor.IdentityProvider(xfcc)
   142  		return err
   143  	}
   144  }