github.com/blend/go-sdk@v1.20220411.3/envoyutil/identity_processor_test.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_test 9 10 import ( 11 "testing" 12 13 sdkAssert "github.com/blend/go-sdk/assert" 14 "github.com/blend/go-sdk/collections" 15 "github.com/blend/go-sdk/spiffeutil" 16 "github.com/blend/go-sdk/uuid" 17 18 "github.com/blend/go-sdk/envoyutil" 19 ) 20 21 func TestOptIdentityType(t *testing.T) { 22 assert := sdkAssert.New(t) 23 24 ip := &envoyutil.IdentityProcessor{} 25 opt := envoyutil.OptIdentityType(envoyutil.ServerIdentity) 26 opt(ip) 27 28 expected := &envoyutil.IdentityProcessor{ 29 Type: envoyutil.ServerIdentity, 30 } 31 assert.Equal(expected, ip) 32 } 33 34 func TestOptAllowedTrustDomains(t *testing.T) { 35 assert := sdkAssert.New(t) 36 37 ip := &envoyutil.IdentityProcessor{ 38 AllowedTrustDomains: []string{"x.invalid"}, 39 } 40 opt := envoyutil.OptAllowedTrustDomains("y.invalid") 41 opt(ip) 42 43 expected := &envoyutil.IdentityProcessor{ 44 AllowedTrustDomains: []string{"x.invalid", "y.invalid"}, 45 } 46 assert.Equal(expected, ip) 47 } 48 49 func TestOptDeniedTrustDomains(t *testing.T) { 50 assert := sdkAssert.New(t) 51 52 ip := &envoyutil.IdentityProcessor{ 53 DeniedTrustDomains: []string{"y.invalid"}, 54 } 55 opt := envoyutil.OptDeniedTrustDomains("z.invalid") 56 opt(ip) 57 58 expected := &envoyutil.IdentityProcessor{ 59 DeniedTrustDomains: []string{"y.invalid", "z.invalid"}, 60 } 61 assert.Equal(expected, ip) 62 } 63 64 func TestOptAllowedIdentities(t *testing.T) { 65 assert := sdkAssert.New(t) 66 67 ip := &envoyutil.IdentityProcessor{ 68 AllowedIdentities: collections.NewSetOfString("x.invalid", "y.invalid"), 69 } 70 opt := envoyutil.OptAllowedIdentities("y.invalid", "z.invalid") 71 opt(ip) 72 73 expected := &envoyutil.IdentityProcessor{ 74 AllowedIdentities: collections.NewSetOfString("x.invalid", "y.invalid", "z.invalid"), 75 } 76 assert.Equal(expected, ip) 77 } 78 79 func TestOptDeniedIdentities(t *testing.T) { 80 assert := sdkAssert.New(t) 81 82 ip := &envoyutil.IdentityProcessor{ 83 DeniedIdentities: collections.NewSetOfString("x.invalid", "y.invalid"), 84 } 85 opt := envoyutil.OptDeniedIdentities("y.invalid", "z.invalid") 86 opt(ip) 87 88 expected := &envoyutil.IdentityProcessor{ 89 DeniedIdentities: collections.NewSetOfString("x.invalid", "y.invalid", "z.invalid"), 90 } 91 assert.Equal(expected, ip) 92 } 93 94 func TestOptFormatIdentity(t *testing.T) { 95 assert := sdkAssert.New(t) 96 97 ip := &envoyutil.IdentityProcessor{ 98 FormatIdentity: makeMockFormatter("not-here"), 99 } 100 sentinel := uuid.V4().ToFullString() 101 formatter := makeMockFormatter(sentinel) 102 opt := envoyutil.OptFormatIdentity(formatter) 103 opt(ip) 104 105 // Can't compare functions for equality, see https://github.com/blend/go-sdk/issues/167 106 // so we make sure our function is as expected. 107 s, err := ip.FormatIdentity(envoyutil.XFCCElement{}, nil) 108 assert.Equal(sentinel, s) 109 assert.Nil(err) 110 } 111 112 func TestIdentityProcessorIdentityProvider(t *testing.T) { 113 assert := sdkAssert.New(t) 114 115 // Empty URI value. 116 ip := envoyutil.IdentityProcessor{} 117 xfcc := envoyutil.XFCCElement{} 118 clientIdentity, err := ip.IdentityProvider(xfcc) 119 assert.Equal("", clientIdentity) 120 assert.True(envoyutil.IsValidationError(err)) 121 var expected error = &envoyutil.XFCCValidationError{ 122 Class: envoyutil.ErrInvalidClientIdentity, 123 XFCC: xfcc.String(), 124 } 125 assert.Equal(expected, err) 126 127 // Invalid URI value. 128 ip = envoyutil.IdentityProcessor{} 129 xfcc = envoyutil.XFCCElement{URI: "spiffe://cluster.local/not-k8s"} 130 clientIdentity, err = ip.IdentityProvider(xfcc) 131 assert.Equal("", clientIdentity) 132 assert.True(envoyutil.IsExtractionError(err)) 133 expected = &envoyutil.XFCCExtractionError{ 134 Class: envoyutil.ErrInvalidClientIdentity, 135 XFCC: xfcc.String(), 136 } 137 assert.Equal(expected, err) 138 139 // Use explicit `FormatIdentity`. 140 ip = envoyutil.IdentityProcessor{ 141 FormatIdentity: makeMockFormatter("sentinel"), 142 } 143 xfcc = envoyutil.XFCCElement{ 144 By: "spiffe://cluster.local/ns/song/sa/lyric", 145 URI: "spiffe://cluster.local/ns/foo/sa/bar", 146 } 147 clientIdentity, err = ip.IdentityProvider(xfcc) 148 assert.Equal("sentinel", clientIdentity) 149 assert.Nil(err) 150 151 // Trust domain in allow list. 152 ip = envoyutil.IdentityProcessor{ 153 AllowedTrustDomains: []string{"cluster.local"}, 154 } 155 clientIdentity, err = ip.IdentityProvider(xfcc) 156 assert.Equal("bar.foo", clientIdentity) 157 assert.Nil(err) 158 159 // Trust domain not in allow list. 160 ip = envoyutil.IdentityProcessor{ 161 AllowedTrustDomains: []string{"not-local.invalid"}, 162 } 163 clientIdentity, err = ip.IdentityProvider(xfcc) 164 assert.Equal("", clientIdentity) 165 assert.True(envoyutil.IsValidationError(err)) 166 expected = &envoyutil.XFCCValidationError{ 167 Class: envoyutil.ErrInvalidClientIdentity, 168 XFCC: xfcc.String(), 169 Metadata: map[string]string{"trustDomain": "cluster.local"}, 170 } 171 assert.Equal(expected, err) 172 173 // Trust domain in deny list. 174 ip = envoyutil.IdentityProcessor{ 175 DeniedTrustDomains: []string{"cluster.local"}, 176 } 177 clientIdentity, err = ip.IdentityProvider(xfcc) 178 assert.Equal("", clientIdentity) 179 assert.True(envoyutil.IsValidationError(err)) 180 expected = &envoyutil.XFCCValidationError{ 181 Class: envoyutil.ErrInvalidClientIdentity, 182 XFCC: xfcc.String(), 183 Metadata: map[string]string{"trustDomain": "cluster.local"}, 184 } 185 assert.Equal(expected, err) 186 187 // Trust domain not in deny list. 188 ip = envoyutil.IdentityProcessor{ 189 DeniedTrustDomains: []string{"not-local.invalid"}, 190 } 191 clientIdentity, err = ip.IdentityProvider(xfcc) 192 assert.Equal("bar.foo", clientIdentity) 193 assert.Nil(err) 194 195 // Client identity not among allow list. 196 ip = envoyutil.IdentityProcessor{ 197 AllowedIdentities: collections.NewSetOfString("ecks.why"), 198 } 199 clientIdentity, err = ip.IdentityProvider(xfcc) 200 assert.Equal("", clientIdentity) 201 assert.True(envoyutil.IsValidationError(err)) 202 expected = &envoyutil.XFCCValidationError{ 203 Class: envoyutil.ErrDeniedClientIdentity, 204 XFCC: xfcc.String(), 205 Metadata: map[string]string{"clientIdentity": "bar.foo"}, 206 } 207 assert.Equal(expected, err) 208 209 // Server identity not among allow list. 210 ip = envoyutil.IdentityProcessor{ 211 Type: envoyutil.ServerIdentity, 212 AllowedIdentities: collections.NewSetOfString("ecks.why"), 213 } 214 serverIdentity, err := ip.IdentityProvider(xfcc) 215 assert.Equal("", serverIdentity) 216 assert.True(envoyutil.IsValidationError(err)) 217 expected = &envoyutil.XFCCValidationError{ 218 Class: envoyutil.ErrDeniedServerIdentity, 219 XFCC: xfcc.String(), 220 Metadata: map[string]string{"serverIdentity": "lyric.song"}, 221 } 222 assert.Equal(expected, err) 223 224 // Client identity among allow list. 225 ip = envoyutil.IdentityProcessor{ 226 AllowedIdentities: collections.NewSetOfString("ecks.why", "bar.foo"), 227 } 228 clientIdentity, err = ip.IdentityProvider(xfcc) 229 assert.Equal("bar.foo", clientIdentity) 230 assert.Nil(err) 231 232 // Extract server identity. 233 ip = envoyutil.IdentityProcessor{ 234 Type: envoyutil.ServerIdentity, 235 } 236 serverIdentity, err = ip.IdentityProvider(xfcc) 237 assert.Equal("lyric.song", serverIdentity) 238 assert.Nil(err) 239 240 // Server identity is contained in deny list. 241 ip = envoyutil.IdentityProcessor{ 242 Type: envoyutil.ServerIdentity, 243 DeniedIdentities: collections.NewSetOfString("lyric.song"), 244 } 245 serverIdentity, err = ip.IdentityProvider(xfcc) 246 assert.Equal("", serverIdentity) 247 assert.True(envoyutil.IsValidationError(err)) 248 expected = &envoyutil.XFCCValidationError{ 249 Class: envoyutil.ErrDeniedServerIdentity, 250 XFCC: xfcc.String(), 251 Metadata: map[string]string{"serverIdentity": "lyric.song"}, 252 } 253 assert.Equal(expected, err) 254 255 // Server identity is **not** contained in deny list. 256 ip = envoyutil.IdentityProcessor{ 257 Type: envoyutil.ServerIdentity, 258 DeniedIdentities: collections.NewSetOfString("not.music"), 259 } 260 serverIdentity, err = ip.IdentityProvider(xfcc) 261 assert.Equal("lyric.song", serverIdentity) 262 assert.Nil(err) 263 264 // Invalid server identity. 265 xfcc = envoyutil.XFCCElement{By: "a=b"} 266 ip = envoyutil.IdentityProcessor{Type: envoyutil.ServerIdentity} 267 serverIdentity, err = ip.IdentityProvider(xfcc) 268 assert.Equal("", serverIdentity) 269 assert.True(envoyutil.IsExtractionError(err)) 270 expected = &envoyutil.XFCCExtractionError{ 271 Class: envoyutil.ErrInvalidServerIdentity, 272 XFCC: xfcc.String(), 273 } 274 assert.Equal(expected, err) 275 } 276 277 func TestIdentityProcessorKubernetesIdentityFormatter(t *testing.T) { 278 assert := sdkAssert.New(t) 279 280 xfcc := envoyutil.XFCCElement{By: "anything", URI: "goes"} 281 282 // Valid identity. 283 ip := &envoyutil.IdentityProcessor{} 284 pu := &spiffeutil.ParsedURI{WorkloadID: "ns/packets/sa/ketchup"} 285 identity, err := ip.KubernetesIdentityFormatter(xfcc, pu) 286 assert.Equal("ketchup.packets", identity) 287 assert.Nil(err) 288 289 // Invalid client identity. 290 pu = &spiffeutil.ParsedURI{WorkloadID: "not-k8s"} 291 clientIdentity, err := ip.KubernetesIdentityFormatter(xfcc, pu) 292 assert.Equal("", clientIdentity) 293 assert.True(envoyutil.IsExtractionError(err)) 294 expected := &envoyutil.XFCCExtractionError{ 295 Class: envoyutil.ErrInvalidClientIdentity, 296 XFCC: xfcc.String(), 297 } 298 assert.Equal(expected, err) 299 300 // Invalid server identity. 301 ip = &envoyutil.IdentityProcessor{Type: envoyutil.ServerIdentity} 302 serverIdentity, err := ip.KubernetesIdentityFormatter(xfcc, pu) 303 assert.Equal("", serverIdentity) 304 assert.True(envoyutil.IsExtractionError(err)) 305 expected = &envoyutil.XFCCExtractionError{ 306 Class: envoyutil.ErrInvalidServerIdentity, 307 XFCC: xfcc.String(), 308 } 309 assert.Equal(expected, err) 310 } 311 312 func makeMockFormatter(identity string) envoyutil.IdentityFormatter { 313 return func(_ envoyutil.XFCCElement, _ *spiffeutil.ParsedURI) (string, error) { 314 return identity, nil 315 } 316 }