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 }