mirror of https://github.com/status-im/consul.git
[NET-3091] Update service intentions to support jwt provider references (#17037)
* [NET-3090] Add new JWT provider config entry * Add initial test cases * update validations for jwt-provider config entry fields * more validation * start improving tests * more tests * Normalize * Improve tests and move validate fns * usage test update * Add split between ent and oss for partitions * fix lint issues * Added retry backoff, fixed tests, removed unused defaults * take into account default partitions * use countTrue and add aliases * omit audiences if empty * fix failing tests * add omit-entry * Add JWT intentions * generate proto * fix deep copy issues * remove extra field * added some tests * more tests * add validation for creating existing jwt * fix nil issue * More tests, fix conflicts and improve memdb call * fix namespace * add aliases * consolidate errors, skip duplicate memdb calls * reworked iteration over config entries * logic improvements from review --------- Co-authored-by: Ronald Ekambi <ronekambi@gmail.com>
This commit is contained in:
parent
ac200cfec8
commit
f4406e69b9
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
memdb "github.com/hashicorp/go-memdb"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
"github.com/hashicorp/consul/agent/configentry"
|
||||
|
@ -592,6 +593,13 @@ func validateProposedConfigEntryInGraph(
|
|||
}
|
||||
case structs.SamenessGroup:
|
||||
case structs.ServiceIntentions:
|
||||
if newEntry != nil {
|
||||
err := validateJWTProvidersExist(tx, kindName, newEntry)
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
case structs.MeshConfig:
|
||||
case structs.ExportedServices:
|
||||
case structs.APIGateway: // TODO Consider checkGatewayClash
|
||||
|
@ -608,6 +616,92 @@ func validateProposedConfigEntryInGraph(
|
|||
return validateProposedConfigEntryInServiceGraph(tx, kindName, newEntry)
|
||||
}
|
||||
|
||||
func getExistingJWTProvidersByName(tx ReadTxn, kn configentry.KindName) (map[string]*structs.JWTProviderConfigEntry, error) {
|
||||
meta := acl.NewEnterpriseMetaWithPartition(
|
||||
kn.EnterpriseMeta.PartitionOrDefault(),
|
||||
acl.DefaultNamespaceName,
|
||||
)
|
||||
|
||||
_, configEntries, err := configEntriesByKindTxn(tx, nil, structs.JWTProvider, &meta)
|
||||
|
||||
providerNames := make(map[string]*structs.JWTProviderConfigEntry)
|
||||
|
||||
for i := range configEntries {
|
||||
entry, ok := configEntries[i].(*structs.JWTProviderConfigEntry)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Invalid type of jwt-provider config entry: %T", configEntries[i])
|
||||
}
|
||||
|
||||
if _, ok := providerNames[entry.Name]; !ok {
|
||||
providerNames[entry.Name] = entry
|
||||
}
|
||||
}
|
||||
|
||||
return providerNames, err
|
||||
}
|
||||
|
||||
func validateJWTProvider(existingProviderNames map[string]*structs.JWTProviderConfigEntry, referencedProviderNames map[string]struct{}) error {
|
||||
var result error
|
||||
|
||||
for referencedProvider := range referencedProviderNames {
|
||||
_, found := existingProviderNames[referencedProvider]
|
||||
if !found {
|
||||
result = multierror.Append(result, fmt.Errorf("Referenced JWT Provider does not exist. Provider Name: %s", referencedProvider)).ErrorOrNil()
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getReferencedProviderNames(j *structs.IntentionJWTRequirement, s []*structs.SourceIntention) map[string]struct{} {
|
||||
providerNames := make(map[string]struct{})
|
||||
|
||||
if j != nil {
|
||||
for _, provider := range j.Providers {
|
||||
if _, ok := providerNames[provider.Name]; !ok {
|
||||
providerNames[provider.Name] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, src := range s {
|
||||
for _, perm := range src.Permissions {
|
||||
if perm.JWT != nil {
|
||||
for _, provider := range perm.JWT.Providers {
|
||||
if _, ok := providerNames[provider.Name]; !ok {
|
||||
providerNames[provider.Name] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return providerNames
|
||||
}
|
||||
|
||||
// This fetches all the jwt-providers config entries and iterates over them
|
||||
// to validate that any provider referenced exists.
|
||||
// This is okay because we assume there are very few jwt-providers per partition
|
||||
func validateJWTProvidersExist(tx ReadTxn, kn configentry.KindName, ce structs.ConfigEntry) error {
|
||||
var result error
|
||||
entry, ok := ce.(*structs.ServiceIntentionsConfigEntry)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid service intention config entry: %T", entry)
|
||||
}
|
||||
|
||||
referencedProvidersNames := getReferencedProviderNames(entry.JWT, entry.Sources)
|
||||
|
||||
if len(referencedProvidersNames) > 0 {
|
||||
jwtProvidersNames, err := getExistingJWTProvidersByName(tx, kn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed retrieval of jwt config entries with err: %v", err)
|
||||
}
|
||||
|
||||
result = multierror.Append(result, validateJWTProvider(jwtProvidersNames, referencedProvidersNames)).ErrorOrNil()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// checkMutualTLSMode validates the MutualTLSMode (in proxy-defaults or
|
||||
// service-defaults) against the AllowEnablingPermissiveMutualTLS setting in the
|
||||
// mesh config entry, as follows:
|
||||
|
|
|
@ -87,6 +87,7 @@ var _ configEntryIndexable = (*structs.ServiceResolverConfigEntry)(nil)
|
|||
var _ configEntryIndexable = (*structs.ServiceRouterConfigEntry)(nil)
|
||||
var _ configEntryIndexable = (*structs.ServiceSplitterConfigEntry)(nil)
|
||||
var _ configEntryIndexable = (*structs.TerminatingGatewayConfigEntry)(nil)
|
||||
var _ configEntryIndexable = (*structs.JWTProviderConfigEntry)(nil)
|
||||
|
||||
func indexFromConfigEntry(c structs.ConfigEntry) ([]byte, error) {
|
||||
if c.GetName() == "" || c.GetKind() == "" {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/lib/stringslice"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
|
||||
"github.com/hashicorp/consul/acl"
|
||||
)
|
||||
|
@ -20,6 +21,8 @@ type ServiceIntentionsConfigEntry struct {
|
|||
|
||||
Sources []*SourceIntention
|
||||
|
||||
JWT *IntentionJWTRequirement `json:",omitempty"`
|
||||
|
||||
Meta map[string]string `json:",omitempty"` // formerly Intention.Meta
|
||||
|
||||
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"` // formerly DestinationNS
|
||||
|
@ -57,6 +60,10 @@ func (e *ServiceIntentionsConfigEntry) Clone() *ServiceIntentionsConfigEntry {
|
|||
e2.Sources[i] = src.Clone()
|
||||
}
|
||||
|
||||
if e.JWT != nil {
|
||||
e2.JWT = e.JWT.Clone()
|
||||
}
|
||||
|
||||
return &e2
|
||||
}
|
||||
|
||||
|
@ -131,6 +138,7 @@ func (e *ServiceIntentionsConfigEntry) ToIntention(src *SourceIntention) *Intent
|
|||
SourceNS: src.NamespaceOrDefault(),
|
||||
SourceName: src.Name,
|
||||
SourceType: src.Type,
|
||||
JWT: e.JWT,
|
||||
Action: src.Action,
|
||||
Permissions: src.Permissions,
|
||||
Meta: meta,
|
||||
|
@ -268,6 +276,79 @@ type SourceIntention struct {
|
|||
Peer string `json:",omitempty"`
|
||||
}
|
||||
|
||||
type IntentionJWTRequirement struct {
|
||||
// Providers is a list of providers to consider when verifying a JWT.
|
||||
Providers []*IntentionJWTProvider `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (e *IntentionJWTRequirement) Clone() *IntentionJWTRequirement {
|
||||
e2 := *e
|
||||
|
||||
e2.Providers = make([]*IntentionJWTProvider, len(e.Providers))
|
||||
for i, src := range e.Providers {
|
||||
e2.Providers[i] = src.Clone()
|
||||
}
|
||||
return &e2
|
||||
}
|
||||
|
||||
func (p *IntentionJWTProvider) Validate() error {
|
||||
if p.Name == "" {
|
||||
return fmt.Errorf("JWT provider name is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *IntentionJWTRequirement) Validate() error {
|
||||
var result error
|
||||
|
||||
for _, provider := range e.Providers {
|
||||
if err := provider.Validate(); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type IntentionJWTProvider struct {
|
||||
// Name is the name of the JWT provider. There MUST be a corresponding
|
||||
// "jwt-provider" config entry with this name.
|
||||
Name string `json:",omitempty"`
|
||||
|
||||
// VerifyClaims is a list of additional claims to verify in a JWT's payload.
|
||||
VerifyClaims []*IntentionJWTClaimVerification `json:",omitempty" alias:"verify_claims"`
|
||||
}
|
||||
|
||||
func (e *IntentionJWTProvider) Clone() *IntentionJWTProvider {
|
||||
e2 := *e
|
||||
|
||||
e2.VerifyClaims = make([]*IntentionJWTClaimVerification, len(e.VerifyClaims))
|
||||
for i, src := range e.VerifyClaims {
|
||||
e2.VerifyClaims[i] = src.Clone()
|
||||
}
|
||||
return &e2
|
||||
}
|
||||
|
||||
type IntentionJWTClaimVerification struct {
|
||||
// Path is the path to the claim in the token JSON.
|
||||
Path []string `json:",omitempty"`
|
||||
|
||||
// Value is the expected value at the given path:
|
||||
// - If the type at the path is a list then we verify
|
||||
// that this value is contained in the list.
|
||||
//
|
||||
// - If the type at the path is a string then we verify
|
||||
// that this value matches.
|
||||
Value string `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (e *IntentionJWTClaimVerification) Clone() *IntentionJWTClaimVerification {
|
||||
e2 := *e
|
||||
|
||||
e2.Path = stringslice.CloneStringSlice(e.Path)
|
||||
return &e2
|
||||
}
|
||||
|
||||
type IntentionPermission struct {
|
||||
Action IntentionAction // required: allow|deny
|
||||
|
||||
|
@ -281,6 +362,8 @@ type IntentionPermission struct {
|
|||
|
||||
// If we ever add Sentinel support, this is one place we may
|
||||
// wish to add it.
|
||||
|
||||
JWT *IntentionJWTRequirement `json:",omitempty"`
|
||||
}
|
||||
|
||||
func (p *IntentionPermission) Clone() *IntentionPermission {
|
||||
|
@ -288,9 +371,21 @@ func (p *IntentionPermission) Clone() *IntentionPermission {
|
|||
if p.HTTP != nil {
|
||||
p2.HTTP = p.HTTP.Clone()
|
||||
}
|
||||
if p.JWT != nil {
|
||||
p2.JWT = p.JWT.Clone()
|
||||
}
|
||||
return &p2
|
||||
}
|
||||
|
||||
func (p *IntentionPermission) Validate() error {
|
||||
var result error
|
||||
if p.JWT != nil {
|
||||
result = p.JWT.Validate()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type IntentionHTTPPermission struct {
|
||||
// PathExact, PathPrefix, and PathRegex are mutually exclusive.
|
||||
PathExact string `json:",omitempty" alias:"path_exact"`
|
||||
|
@ -562,6 +657,12 @@ func (e *ServiceIntentionsConfigEntry) validate(legacyWrite bool) error {
|
|||
|
||||
destIsWild := e.HasWildcardDestination()
|
||||
|
||||
if e.JWT != nil {
|
||||
if err := e.JWT.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if legacyWrite {
|
||||
if len(e.Meta) > 0 {
|
||||
return fmt.Errorf("Meta must be omitted for legacy intention writes")
|
||||
|
@ -762,6 +863,10 @@ func (e *ServiceIntentionsConfigEntry) validate(legacyWrite bool) error {
|
|||
if permParts == 0 {
|
||||
return fmt.Errorf(errorPrefix+" should not be empty", i, j)
|
||||
}
|
||||
|
||||
if err := perm.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
psn := PeeredServiceName{Peer: src.Peer, ServiceName: src.SourceServiceName()}
|
||||
|
|
|
@ -1265,6 +1265,153 @@ func TestServiceIntentionsConfigEntry(t *testing.T) {
|
|||
},
|
||||
validateErr: `Sources[1] defines peer("peer1") "` + fooName.String() + `" more than once`,
|
||||
},
|
||||
"JWT - missing provider name": {
|
||||
entry: &ServiceIntentionsConfigEntry{
|
||||
Kind: ServiceIntentions,
|
||||
Name: "test",
|
||||
JWT: &IntentionJWTRequirement{
|
||||
Providers: []*IntentionJWTProvider{
|
||||
{
|
||||
VerifyClaims: []*IntentionJWTClaimVerification{
|
||||
{
|
||||
Value: "api.apps.test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validateErr: `JWT provider name is required`,
|
||||
},
|
||||
"JWT - missing 1 provider name with multiple providers": {
|
||||
entry: &ServiceIntentionsConfigEntry{
|
||||
Kind: ServiceIntentions,
|
||||
Name: "test",
|
||||
JWT: &IntentionJWTRequirement{
|
||||
Providers: []*IntentionJWTProvider{
|
||||
{
|
||||
VerifyClaims: []*IntentionJWTClaimVerification{
|
||||
{
|
||||
Path: []string{"aud"},
|
||||
Value: "another-api.test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "okta",
|
||||
VerifyClaims: []*IntentionJWTClaimVerification{
|
||||
{
|
||||
Path: []string{"aud"},
|
||||
Value: "api.apps.test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validateErr: `JWT provider name is required`,
|
||||
},
|
||||
"JWT - missing provider name under permissions": {
|
||||
entry: &ServiceIntentionsConfigEntry{
|
||||
Kind: ServiceIntentions,
|
||||
Name: "test",
|
||||
Sources: []*SourceIntention{
|
||||
{
|
||||
Name: "foo",
|
||||
Permissions: []*IntentionPermission{
|
||||
{
|
||||
Action: IntentionActionAllow,
|
||||
HTTP: &IntentionHTTPPermission{
|
||||
PathPrefix: "/foo",
|
||||
Header: []IntentionHTTPHeaderPermission{
|
||||
{
|
||||
Name: "x-abc",
|
||||
Exact: "foo",
|
||||
},
|
||||
{
|
||||
Name: "x-xyz",
|
||||
Present: true,
|
||||
Invert: true,
|
||||
},
|
||||
},
|
||||
Methods: []string{"POST", "PUT", "GET"},
|
||||
},
|
||||
JWT: &IntentionJWTRequirement{
|
||||
Providers: []*IntentionJWTProvider{
|
||||
{
|
||||
VerifyClaims: []*IntentionJWTClaimVerification{
|
||||
{
|
||||
Path: []string{"aud"},
|
||||
Value: "another-api.test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validateErr: `JWT provider name is required`,
|
||||
},
|
||||
"valid JWTs": {
|
||||
entry: &ServiceIntentionsConfigEntry{
|
||||
Kind: ServiceIntentions,
|
||||
Name: "test",
|
||||
JWT: &IntentionJWTRequirement{
|
||||
Providers: []*IntentionJWTProvider{
|
||||
{
|
||||
Name: "okta",
|
||||
VerifyClaims: []*IntentionJWTClaimVerification{
|
||||
{
|
||||
Path: []string{"aud"},
|
||||
Value: "another-api.test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Sources: []*SourceIntention{
|
||||
{
|
||||
Name: "foo",
|
||||
Permissions: []*IntentionPermission{
|
||||
{
|
||||
Action: IntentionActionAllow,
|
||||
HTTP: &IntentionHTTPPermission{
|
||||
PathPrefix: "/foo",
|
||||
Header: []IntentionHTTPHeaderPermission{
|
||||
{
|
||||
Name: "x-abc",
|
||||
Exact: "foo",
|
||||
},
|
||||
{
|
||||
Name: "x-xyz",
|
||||
Present: true,
|
||||
Invert: true,
|
||||
},
|
||||
},
|
||||
Methods: []string{"POST", "PUT", "GET"},
|
||||
},
|
||||
JWT: &IntentionJWTRequirement{
|
||||
Providers: []*IntentionJWTProvider{
|
||||
{
|
||||
Name: "okta",
|
||||
VerifyClaims: []*IntentionJWTClaimVerification{
|
||||
{
|
||||
Path: []string{"aud"},
|
||||
Value: "another-api.test.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
tc := tc
|
||||
|
|
|
@ -78,6 +78,9 @@ type Intention struct {
|
|||
// service-intentions config entry directly.
|
||||
Permissions []*IntentionPermission `bexpr:"-" json:",omitempty"`
|
||||
|
||||
// JWT specifies JWT authn that applies to incoming requests.
|
||||
JWT *IntentionJWTRequirement `bexpr:"-" json:",omitempty"`
|
||||
|
||||
// DefaultAddr is not used.
|
||||
// Deprecated: DefaultAddr is not used and may be removed in a future version.
|
||||
DefaultAddr string `bexpr:"-" codec:",omitempty" json:",omitempty"`
|
||||
|
|
|
@ -565,6 +565,34 @@ func (o *Intention) DeepCopy() *Intention {
|
|||
}
|
||||
}
|
||||
}
|
||||
if o.JWT != nil {
|
||||
cp.JWT = new(IntentionJWTRequirement)
|
||||
*cp.JWT = *o.JWT
|
||||
if o.JWT.Providers != nil {
|
||||
cp.JWT.Providers = make([]*IntentionJWTProvider, len(o.JWT.Providers))
|
||||
copy(cp.JWT.Providers, o.JWT.Providers)
|
||||
for i4 := range o.JWT.Providers {
|
||||
if o.JWT.Providers[i4] != nil {
|
||||
cp.JWT.Providers[i4] = new(IntentionJWTProvider)
|
||||
*cp.JWT.Providers[i4] = *o.JWT.Providers[i4]
|
||||
if o.JWT.Providers[i4].VerifyClaims != nil {
|
||||
cp.JWT.Providers[i4].VerifyClaims = make([]*IntentionJWTClaimVerification, len(o.JWT.Providers[i4].VerifyClaims))
|
||||
copy(cp.JWT.Providers[i4].VerifyClaims, o.JWT.Providers[i4].VerifyClaims)
|
||||
for i7 := range o.JWT.Providers[i4].VerifyClaims {
|
||||
if o.JWT.Providers[i4].VerifyClaims[i7] != nil {
|
||||
cp.JWT.Providers[i4].VerifyClaims[i7] = new(IntentionJWTClaimVerification)
|
||||
*cp.JWT.Providers[i4].VerifyClaims[i7] = *o.JWT.Providers[i4].VerifyClaims[i7]
|
||||
if o.JWT.Providers[i4].VerifyClaims[i7].Path != nil {
|
||||
cp.JWT.Providers[i4].VerifyClaims[i7].Path = make([]string, len(o.JWT.Providers[i4].VerifyClaims[i7].Path))
|
||||
copy(cp.JWT.Providers[i4].VerifyClaims[i7].Path, o.JWT.Providers[i4].VerifyClaims[i7].Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.Meta != nil {
|
||||
cp.Meta = make(map[string]string, len(o.Meta))
|
||||
for k2, v2 := range o.Meta {
|
||||
|
@ -593,6 +621,34 @@ func (o *IntentionPermission) DeepCopy() *IntentionPermission {
|
|||
copy(cp.HTTP.Methods, o.HTTP.Methods)
|
||||
}
|
||||
}
|
||||
if o.JWT != nil {
|
||||
cp.JWT = new(IntentionJWTRequirement)
|
||||
*cp.JWT = *o.JWT
|
||||
if o.JWT.Providers != nil {
|
||||
cp.JWT.Providers = make([]*IntentionJWTProvider, len(o.JWT.Providers))
|
||||
copy(cp.JWT.Providers, o.JWT.Providers)
|
||||
for i4 := range o.JWT.Providers {
|
||||
if o.JWT.Providers[i4] != nil {
|
||||
cp.JWT.Providers[i4] = new(IntentionJWTProvider)
|
||||
*cp.JWT.Providers[i4] = *o.JWT.Providers[i4]
|
||||
if o.JWT.Providers[i4].VerifyClaims != nil {
|
||||
cp.JWT.Providers[i4].VerifyClaims = make([]*IntentionJWTClaimVerification, len(o.JWT.Providers[i4].VerifyClaims))
|
||||
copy(cp.JWT.Providers[i4].VerifyClaims, o.JWT.Providers[i4].VerifyClaims)
|
||||
for i7 := range o.JWT.Providers[i4].VerifyClaims {
|
||||
if o.JWT.Providers[i4].VerifyClaims[i7] != nil {
|
||||
cp.JWT.Providers[i4].VerifyClaims[i7] = new(IntentionJWTClaimVerification)
|
||||
*cp.JWT.Providers[i4].VerifyClaims[i7] = *o.JWT.Providers[i4].VerifyClaims[i7]
|
||||
if o.JWT.Providers[i4].VerifyClaims[i7].Path != nil {
|
||||
cp.JWT.Providers[i4].VerifyClaims[i7].Path = make([]string, len(o.JWT.Providers[i4].VerifyClaims[i7].Path))
|
||||
copy(cp.JWT.Providers[i4].VerifyClaims[i7].Path, o.JWT.Providers[i4].VerifyClaims[i7].Path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return &cp
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ type ServiceIntentionsConfigEntry struct {
|
|||
Namespace string `json:",omitempty"`
|
||||
|
||||
Sources []*SourceIntention
|
||||
JWT *IntentionJWTRequirement `json:",omitempty"`
|
||||
|
||||
Meta map[string]string `json:",omitempty"`
|
||||
|
||||
|
@ -47,6 +48,7 @@ func (e *ServiceIntentionsConfigEntry) GetModifyIndex() uint64 { return e.Mo
|
|||
type IntentionPermission struct {
|
||||
Action IntentionAction
|
||||
HTTP *IntentionHTTPPermission `json:",omitempty"`
|
||||
JWT *IntentionJWTRequirement `json:",omitempty"`
|
||||
}
|
||||
|
||||
type IntentionHTTPPermission struct {
|
||||
|
@ -68,3 +70,30 @@ type IntentionHTTPHeaderPermission struct {
|
|||
Regex string `json:",omitempty"`
|
||||
Invert bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type IntentionJWTRequirement struct {
|
||||
// Providers is a list of providers to consider when verifying a JWT.
|
||||
Providers []*IntentionJWTProvider `json:",omitempty"`
|
||||
}
|
||||
|
||||
type IntentionJWTProvider struct {
|
||||
// Name is the name of the JWT provider. There MUST be a corresponding
|
||||
// "jwt-provider" config entry with this name.
|
||||
Name string `json:",omitempty"`
|
||||
|
||||
// VerifyClaims is a list of additional claims to verify in a JWT's payload.
|
||||
VerifyClaims []*IntentionJWTClaimVerification `json:",omitempty" alias:"verify_claims"`
|
||||
}
|
||||
|
||||
type IntentionJWTClaimVerification struct {
|
||||
// Path is the path to the claim in the token JSON.
|
||||
Path []string `json:",omitempty"`
|
||||
|
||||
// Value is the expected value at the given path:
|
||||
// - If the type at the path is a list then we verify
|
||||
// that this value is contained in the list.
|
||||
//
|
||||
// - If the type at the path is a string then we verify
|
||||
// that this value matches.
|
||||
Value string `json:",omitempty"`
|
||||
}
|
||||
|
|
|
@ -944,6 +944,82 @@ func IntentionHTTPPermissionFromStructs(t *structs.IntentionHTTPPermission, s *I
|
|||
}
|
||||
s.Methods = t.Methods
|
||||
}
|
||||
func IntentionJWTClaimVerificationToStructs(s *IntentionJWTClaimVerification, t *structs.IntentionJWTClaimVerification) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
t.Path = s.Path
|
||||
t.Value = s.Value
|
||||
}
|
||||
func IntentionJWTClaimVerificationFromStructs(t *structs.IntentionJWTClaimVerification, s *IntentionJWTClaimVerification) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.Path = t.Path
|
||||
s.Value = t.Value
|
||||
}
|
||||
func IntentionJWTProviderToStructs(s *IntentionJWTProvider, t *structs.IntentionJWTProvider) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
t.Name = s.Name
|
||||
{
|
||||
t.VerifyClaims = make([]*structs.IntentionJWTClaimVerification, len(s.VerifyClaims))
|
||||
for i := range s.VerifyClaims {
|
||||
if s.VerifyClaims[i] != nil {
|
||||
var x structs.IntentionJWTClaimVerification
|
||||
IntentionJWTClaimVerificationToStructs(s.VerifyClaims[i], &x)
|
||||
t.VerifyClaims[i] = &x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func IntentionJWTProviderFromStructs(t *structs.IntentionJWTProvider, s *IntentionJWTProvider) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
s.Name = t.Name
|
||||
{
|
||||
s.VerifyClaims = make([]*IntentionJWTClaimVerification, len(t.VerifyClaims))
|
||||
for i := range t.VerifyClaims {
|
||||
if t.VerifyClaims[i] != nil {
|
||||
var x IntentionJWTClaimVerification
|
||||
IntentionJWTClaimVerificationFromStructs(t.VerifyClaims[i], &x)
|
||||
s.VerifyClaims[i] = &x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func IntentionJWTRequirementToStructs(s *IntentionJWTRequirement, t *structs.IntentionJWTRequirement) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
{
|
||||
t.Providers = make([]*structs.IntentionJWTProvider, len(s.Providers))
|
||||
for i := range s.Providers {
|
||||
if s.Providers[i] != nil {
|
||||
var x structs.IntentionJWTProvider
|
||||
IntentionJWTProviderToStructs(s.Providers[i], &x)
|
||||
t.Providers[i] = &x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func IntentionJWTRequirementFromStructs(t *structs.IntentionJWTRequirement, s *IntentionJWTRequirement) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
{
|
||||
s.Providers = make([]*IntentionJWTProvider, len(t.Providers))
|
||||
for i := range t.Providers {
|
||||
if t.Providers[i] != nil {
|
||||
var x IntentionJWTProvider
|
||||
IntentionJWTProviderFromStructs(t.Providers[i], &x)
|
||||
s.Providers[i] = &x
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func IntentionPermissionToStructs(s *IntentionPermission, t *structs.IntentionPermission) {
|
||||
if s == nil {
|
||||
return
|
||||
|
@ -954,6 +1030,11 @@ func IntentionPermissionToStructs(s *IntentionPermission, t *structs.IntentionPe
|
|||
IntentionHTTPPermissionToStructs(s.HTTP, &x)
|
||||
t.HTTP = &x
|
||||
}
|
||||
if s.JWT != nil {
|
||||
var x structs.IntentionJWTRequirement
|
||||
IntentionJWTRequirementToStructs(s.JWT, &x)
|
||||
t.JWT = &x
|
||||
}
|
||||
}
|
||||
func IntentionPermissionFromStructs(t *structs.IntentionPermission, s *IntentionPermission) {
|
||||
if s == nil {
|
||||
|
@ -965,6 +1046,11 @@ func IntentionPermissionFromStructs(t *structs.IntentionPermission, s *Intention
|
|||
IntentionHTTPPermissionFromStructs(t.HTTP, &x)
|
||||
s.HTTP = &x
|
||||
}
|
||||
if t.JWT != nil {
|
||||
var x IntentionJWTRequirement
|
||||
IntentionJWTRequirementFromStructs(t.JWT, &x)
|
||||
s.JWT = &x
|
||||
}
|
||||
}
|
||||
func LeastRequestConfigToStructs(s *LeastRequestConfig, t *structs.LeastRequestConfig) {
|
||||
if s == nil {
|
||||
|
@ -1350,6 +1436,11 @@ func ServiceIntentionsToStructs(s *ServiceIntentions, t *structs.ServiceIntentio
|
|||
}
|
||||
}
|
||||
}
|
||||
if s.JWT != nil {
|
||||
var x structs.IntentionJWTRequirement
|
||||
IntentionJWTRequirementToStructs(s.JWT, &x)
|
||||
t.JWT = &x
|
||||
}
|
||||
t.Meta = s.Meta
|
||||
}
|
||||
func ServiceIntentionsFromStructs(t *structs.ServiceIntentionsConfigEntry, s *ServiceIntentions) {
|
||||
|
@ -1366,6 +1457,11 @@ func ServiceIntentionsFromStructs(t *structs.ServiceIntentionsConfigEntry, s *Se
|
|||
}
|
||||
}
|
||||
}
|
||||
if t.JWT != nil {
|
||||
var x IntentionJWTRequirement
|
||||
IntentionJWTRequirementFromStructs(t.JWT, &x)
|
||||
s.JWT = &x
|
||||
}
|
||||
s.Meta = t.Meta
|
||||
}
|
||||
func ServiceResolverToStructs(s *ServiceResolver, t *structs.ServiceResolverConfigEntry) {
|
||||
|
|
|
@ -287,6 +287,36 @@ func (msg *ServiceIntentions) UnmarshalBinary(b []byte) error {
|
|||
return proto.Unmarshal(b, msg)
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *IntentionJWTRequirement) MarshalBinary() ([]byte, error) {
|
||||
return proto.Marshal(msg)
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *IntentionJWTRequirement) UnmarshalBinary(b []byte) error {
|
||||
return proto.Unmarshal(b, msg)
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *IntentionJWTProvider) MarshalBinary() ([]byte, error) {
|
||||
return proto.Marshal(msg)
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *IntentionJWTProvider) UnmarshalBinary(b []byte) error {
|
||||
return proto.Unmarshal(b, msg)
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *IntentionJWTClaimVerification) MarshalBinary() ([]byte, error) {
|
||||
return proto.Marshal(msg)
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (msg *IntentionJWTClaimVerification) UnmarshalBinary(b []byte) error {
|
||||
return proto.Unmarshal(b, msg)
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (msg *SourceIntention) MarshalBinary() ([]byte, error) {
|
||||
return proto.Marshal(msg)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -374,6 +374,36 @@ message HTTPHeaderModifiers {
|
|||
message ServiceIntentions {
|
||||
repeated SourceIntention Sources = 1;
|
||||
map<string, string> Meta = 2;
|
||||
IntentionJWTRequirement JWT = 3;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
//
|
||||
// target=github.com/hashicorp/consul/agent/structs.IntentionJWTRequirement
|
||||
// output=config_entry.gen.go
|
||||
// name=Structs
|
||||
message IntentionJWTRequirement {
|
||||
repeated IntentionJWTProvider Providers = 1;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
//
|
||||
// target=github.com/hashicorp/consul/agent/structs.IntentionJWTProvider
|
||||
// output=config_entry.gen.go
|
||||
// name=Structs
|
||||
message IntentionJWTProvider {
|
||||
string Name = 1;
|
||||
repeated IntentionJWTClaimVerification VerifyClaims = 2;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
//
|
||||
// target=github.com/hashicorp/consul/agent/structs.IntentionJWTClaimVerification
|
||||
// output=config_entry.gen.go
|
||||
// name=Structs
|
||||
message IntentionJWTClaimVerification {
|
||||
repeated string Path = 1;
|
||||
string Value = 2;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
|
@ -420,6 +450,7 @@ message IntentionPermission {
|
|||
// mog: func-to=intentionActionToStructs func-from=intentionActionFromStructs
|
||||
IntentionAction Action = 1;
|
||||
IntentionHTTPPermission HTTP = 2;
|
||||
IntentionJWTRequirement JWT = 3;
|
||||
}
|
||||
|
||||
// mog annotation:
|
||||
|
|
Loading…
Reference in New Issue