* Expose JWKS cluster config through JWTProviderConfigEntry * fix typos, rename trustedCa to trustedCA
This commit is contained in:
parent
1b88ffef33
commit
f9f2a5037f
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
mesh: Expose remote jwks cluster configuration through jwt-provider config entry
|
||||||
|
```
|
|
@ -54,6 +54,26 @@ func (o *ConfigSnapshot) DeepCopy() *ConfigSnapshot {
|
||||||
*cp_JWTProviders_v2.JSONWebKeySet.Remote.RetryPolicy.RetryPolicyBackOff = *v2.JSONWebKeySet.Remote.RetryPolicy.RetryPolicyBackOff
|
*cp_JWTProviders_v2.JSONWebKeySet.Remote.RetryPolicy.RetryPolicyBackOff = *v2.JSONWebKeySet.Remote.RetryPolicy.RetryPolicyBackOff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if v2.JSONWebKeySet.Remote.JWKSCluster != nil {
|
||||||
|
cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster = new(structs.JWKSCluster)
|
||||||
|
*cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster = *v2.JSONWebKeySet.Remote.JWKSCluster
|
||||||
|
if v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates != nil {
|
||||||
|
cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates = new(structs.JWKSTLSCertificate)
|
||||||
|
*cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates = *v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates
|
||||||
|
if v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.CaCertificateProviderInstance != nil {
|
||||||
|
cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.CaCertificateProviderInstance = new(structs.JWKSTLSCertProviderInstance)
|
||||||
|
*cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.CaCertificateProviderInstance = *v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.CaCertificateProviderInstance
|
||||||
|
}
|
||||||
|
if v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA != nil {
|
||||||
|
cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA = new(structs.JWKSTLSCertTrustedCA)
|
||||||
|
*cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA = *v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA
|
||||||
|
if v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA.InlineBytes != nil {
|
||||||
|
cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA.InlineBytes = make([]byte, len(v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA.InlineBytes))
|
||||||
|
copy(cp_JWTProviders_v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA.InlineBytes, v2.JSONWebKeySet.Remote.JWKSCluster.TLSCertificates.TrustedCA.InlineBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v2.Audiences != nil {
|
if v2.Audiences != nil {
|
||||||
|
|
|
@ -15,6 +15,12 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultClockSkewSeconds = 30
|
DefaultClockSkewSeconds = 30
|
||||||
|
|
||||||
|
DiscoveryTypeStrictDNS ClusterDiscoveryType = "STRICT_DNS"
|
||||||
|
DiscoveryTypeStatic ClusterDiscoveryType = "STATIC"
|
||||||
|
DiscoveryTypeLogicalDNS ClusterDiscoveryType = "LOGICAL_DNS"
|
||||||
|
DiscoveryTypeEDS ClusterDiscoveryType = "EDS"
|
||||||
|
DiscoveryTypeOriginalDST ClusterDiscoveryType = "ORIGINAL_DST"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JWTProviderConfigEntry struct {
|
type JWTProviderConfigEntry struct {
|
||||||
|
@ -97,7 +103,7 @@ func (location *JWTLocation) Validate() error {
|
||||||
hasCookie := location.Cookie != nil
|
hasCookie := location.Cookie != nil
|
||||||
|
|
||||||
if countTrue(hasHeader, hasQueryParam, hasCookie) != 1 {
|
if countTrue(hasHeader, hasQueryParam, hasCookie) != 1 {
|
||||||
return fmt.Errorf("Must set exactly one of: JWT location header, query param or cookie")
|
return fmt.Errorf("must set exactly one of: JWT location header, query param or cookie")
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasHeader {
|
if hasHeader {
|
||||||
|
@ -205,7 +211,7 @@ func (ks *LocalJWKS) Validate() error {
|
||||||
hasJWKS := ks.JWKS != ""
|
hasJWKS := ks.JWKS != ""
|
||||||
|
|
||||||
if countTrue(hasFilename, hasJWKS) != 1 {
|
if countTrue(hasFilename, hasJWKS) != 1 {
|
||||||
return fmt.Errorf("Must specify exactly one of String or filename for local keyset")
|
return fmt.Errorf("must specify exactly one of String or filename for local keyset")
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasJWKS {
|
if hasJWKS {
|
||||||
|
@ -245,6 +251,9 @@ type RemoteJWKS struct {
|
||||||
//
|
//
|
||||||
// There is no retry by default.
|
// There is no retry by default.
|
||||||
RetryPolicy *JWKSRetryPolicy `json:",omitempty" alias:"retry_policy"`
|
RetryPolicy *JWKSRetryPolicy `json:",omitempty" alias:"retry_policy"`
|
||||||
|
|
||||||
|
// JWKSCluster defines how the specified Remote JWKS URI is to be fetched.
|
||||||
|
JWKSCluster *JWKSCluster `json:",omitempty" alias:"jwks_cluster"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ks *RemoteJWKS) Validate() error {
|
func (ks *RemoteJWKS) Validate() error {
|
||||||
|
@ -257,9 +266,127 @@ func (ks *RemoteJWKS) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ks.RetryPolicy != nil && ks.RetryPolicy.RetryPolicyBackOff != nil {
|
if ks.RetryPolicy != nil && ks.RetryPolicy.RetryPolicyBackOff != nil {
|
||||||
return ks.RetryPolicy.RetryPolicyBackOff.Validate()
|
err := ks.RetryPolicy.RetryPolicyBackOff.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ks.JWKSCluster != nil {
|
||||||
|
return ks.JWKSCluster.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWKSCluster struct {
|
||||||
|
// DiscoveryType refers to the service discovery type to use for resolving the cluster.
|
||||||
|
//
|
||||||
|
// This defaults to STRICT_DNS.
|
||||||
|
// Other options include STATIC, LOGICAL_DNS, EDS or ORIGINAL_DST.
|
||||||
|
DiscoveryType ClusterDiscoveryType `json:",omitempty" alias:"discovery_type"`
|
||||||
|
|
||||||
|
// TLSCertificates refers to the data containing certificate authority certificates to use
|
||||||
|
// in verifying a presented peer certificate.
|
||||||
|
// If not specified and a peer certificate is presented it will not be verified.
|
||||||
|
//
|
||||||
|
// Must be either CaCertificateProviderInstance or TrustedCA.
|
||||||
|
TLSCertificates *JWKSTLSCertificate `json:",omitempty" alias:"tls_certificates"`
|
||||||
|
|
||||||
|
// The timeout for new network connections to hosts in the cluster.
|
||||||
|
// If not set, a default value of 5s will be used.
|
||||||
|
ConnectTimeout time.Duration `json:",omitempty" alias:"connect_timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterDiscoveryType string
|
||||||
|
|
||||||
|
func (d ClusterDiscoveryType) Validate() error {
|
||||||
|
switch d {
|
||||||
|
case DiscoveryTypeStatic, DiscoveryTypeStrictDNS, DiscoveryTypeLogicalDNS, DiscoveryTypeEDS, DiscoveryTypeOriginalDST:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported jwks cluster discovery type: %q", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JWKSCluster) Validate() error {
|
||||||
|
if c.DiscoveryType != "" {
|
||||||
|
err := c.DiscoveryType.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TLSCertificates != nil {
|
||||||
|
return c.TLSCertificates.Validate()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWKSTLSCertificate refers to the data containing certificate authority certificates to use
|
||||||
|
// in verifying a presented peer certificate.
|
||||||
|
// If not specified and a peer certificate is presented it will not be verified.
|
||||||
|
//
|
||||||
|
// Must be either CaCertificateProviderInstance or TrustedCA.
|
||||||
|
type JWKSTLSCertificate struct {
|
||||||
|
// CaCertificateProviderInstance Certificate provider instance for fetching TLS certificates.
|
||||||
|
CaCertificateProviderInstance *JWKSTLSCertProviderInstance `json:",omitempty" alias:"ca_certificate_provider_instance"`
|
||||||
|
|
||||||
|
// TrustedCA defines TLS certificate data containing certificate authority certificates
|
||||||
|
// to use in verifying a presented peer certificate.
|
||||||
|
//
|
||||||
|
// Exactly one of Filename, EnvironmentVariable, InlineString or InlineBytes must be specified.
|
||||||
|
TrustedCA *JWKSTLSCertTrustedCA `json:",omitempty" alias:"trusted_ca"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JWKSTLSCertificate) Validate() error {
|
||||||
|
hasProviderInstance := c.CaCertificateProviderInstance != nil
|
||||||
|
hasTrustedCA := c.TrustedCA != nil
|
||||||
|
|
||||||
|
if countTrue(hasProviderInstance, hasTrustedCA) != 1 {
|
||||||
|
return fmt.Errorf("must specify exactly one of: CaCertificateProviderInstance or TrustedCA for JKWS' TLSCertificates")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.TrustedCA != nil {
|
||||||
|
return c.TrustedCA.Validate()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWKSTLSCertProviderInstance struct {
|
||||||
|
// InstanceName refers to the certificate provider instance name
|
||||||
|
//
|
||||||
|
// The default value is "default".
|
||||||
|
InstanceName string `json:",omitempty" alias:"instance_name"`
|
||||||
|
|
||||||
|
// CertificateName is used to specify certificate instances or types. For example, "ROOTCA" to specify
|
||||||
|
// a root-certificate (validation context) or "example.com" to specify a certificate for a
|
||||||
|
// particular domain.
|
||||||
|
//
|
||||||
|
// The default value is the empty string.
|
||||||
|
CertificateName string `json:",omitempty" alias:"certificate_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWKSTLSCertTrustedCA defines TLS certificate data containing certificate authority certificates
|
||||||
|
// to use in verifying a presented peer certificate.
|
||||||
|
//
|
||||||
|
// Exactly one of Filename, EnvironmentVariable, InlineString or InlineBytes must be specified.
|
||||||
|
type JWKSTLSCertTrustedCA struct {
|
||||||
|
Filename string `json:",omitempty" alias:"filename"`
|
||||||
|
EnvironmentVariable string `json:",omitempty" alias:"environment_variable"`
|
||||||
|
InlineString string `json:",omitempty" alias:"inline_string"`
|
||||||
|
InlineBytes []byte `json:",omitempty" alias:"inline_bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JWKSTLSCertTrustedCA) Validate() error {
|
||||||
|
hasFilename := c.Filename != ""
|
||||||
|
hasEnv := c.EnvironmentVariable != ""
|
||||||
|
hasInlineBytes := len(c.InlineBytes) > 0
|
||||||
|
hasInlineString := c.InlineString != ""
|
||||||
|
|
||||||
|
if countTrue(hasFilename, hasEnv, hasInlineString, hasInlineBytes) != 1 {
|
||||||
|
return fmt.Errorf("must specify exactly one of: Filename, EnvironmentVariable, InlineString or InlineBytes for JWKS' TrustedCA")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +420,7 @@ type RetryPolicyBackOff struct {
|
||||||
func (r *RetryPolicyBackOff) Validate() error {
|
func (r *RetryPolicyBackOff) Validate() error {
|
||||||
|
|
||||||
if (r.MaxInterval != 0) && (r.BaseInterval > r.MaxInterval) {
|
if (r.MaxInterval != 0) && (r.BaseInterval > r.MaxInterval) {
|
||||||
return fmt.Errorf("Retry policy backoff's MaxInterval should be greater or equal to BaseInterval")
|
return fmt.Errorf("retry policy backoff's MaxInterval should be greater or equal to BaseInterval")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -339,7 +466,7 @@ func (jwks *JSONWebKeySet) Validate() error {
|
||||||
hasRemoteKeySet := jwks.Remote != nil
|
hasRemoteKeySet := jwks.Remote != nil
|
||||||
|
|
||||||
if countTrue(hasLocalKeySet, hasRemoteKeySet) != 1 {
|
if countTrue(hasLocalKeySet, hasRemoteKeySet) != 1 {
|
||||||
return fmt.Errorf("Must specify exactly one of Local or Remote JSON Web key set")
|
return fmt.Errorf("must specify exactly one of Local or Remote JSON Web key set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasRemoteKeySet {
|
if hasRemoteKeySet {
|
||||||
|
|
|
@ -22,6 +22,7 @@ func newTestAuthz(t *testing.T, src string) acl.Authorizer {
|
||||||
|
|
||||||
var tenSeconds time.Duration = 10 * time.Second
|
var tenSeconds time.Duration = 10 * time.Second
|
||||||
var hundredSeconds time.Duration = 100 * time.Second
|
var hundredSeconds time.Duration = 100 * time.Second
|
||||||
|
var connectTimeout = time.Duration(5) * time.Second
|
||||||
|
|
||||||
func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
defaultMeta := DefaultEnterpriseMetaInDefaultPartition()
|
defaultMeta := DefaultEnterpriseMetaInDefaultPartition()
|
||||||
|
@ -113,7 +114,7 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
Name: "okta",
|
Name: "okta",
|
||||||
JSONWebKeySet: &JSONWebKeySet{},
|
JSONWebKeySet: &JSONWebKeySet{},
|
||||||
},
|
},
|
||||||
validateErr: "Must specify exactly one of Local or Remote JSON Web key set",
|
validateErr: "must specify exactly one of Local or Remote JSON Web key set",
|
||||||
},
|
},
|
||||||
"invalid jwt-provider - local jwks with non-encoded base64 jwks": {
|
"invalid jwt-provider - local jwks with non-encoded base64 jwks": {
|
||||||
entry: &JWTProviderConfigEntry{
|
entry: &JWTProviderConfigEntry{
|
||||||
|
@ -138,7 +139,7 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
Remote: &RemoteJWKS{},
|
Remote: &RemoteJWKS{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validateErr: "Must specify exactly one of Local or Remote JSON Web key set",
|
validateErr: "must specify exactly one of Local or Remote JSON Web key set",
|
||||||
},
|
},
|
||||||
"invalid jwt-provider - local jwks string and filename both set": {
|
"invalid jwt-provider - local jwks string and filename both set": {
|
||||||
entry: &JWTProviderConfigEntry{
|
entry: &JWTProviderConfigEntry{
|
||||||
|
@ -151,7 +152,7 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validateErr: "Must specify exactly one of String or filename for local keyset",
|
validateErr: "must specify exactly one of String or filename for local keyset",
|
||||||
},
|
},
|
||||||
"invalid jwt-provider - remote jwks missing uri": {
|
"invalid jwt-provider - remote jwks missing uri": {
|
||||||
entry: &JWTProviderConfigEntry{
|
entry: &JWTProviderConfigEntry{
|
||||||
|
@ -202,7 +203,7 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validateErr: "Must set exactly one of: JWT location header, query param or cookie",
|
validateErr: "must set exactly one of: JWT location header, query param or cookie",
|
||||||
},
|
},
|
||||||
"invalid jwt-provider - Remote JWKS retry policy maxinterval < baseInterval": {
|
"invalid jwt-provider - Remote JWKS retry policy maxinterval < baseInterval": {
|
||||||
entry: &JWTProviderConfigEntry{
|
entry: &JWTProviderConfigEntry{
|
||||||
|
@ -221,7 +222,63 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validateErr: "Retry policy backoff's MaxInterval should be greater or equal to BaseInterval",
|
validateErr: "retry policy backoff's MaxInterval should be greater or equal to BaseInterval",
|
||||||
|
},
|
||||||
|
"invalid jwt-provider - Remote JWKS cluster wrong discovery type": {
|
||||||
|
entry: &JWTProviderConfigEntry{
|
||||||
|
Kind: JWTProvider,
|
||||||
|
Name: "okta",
|
||||||
|
JSONWebKeySet: &JSONWebKeySet{
|
||||||
|
Remote: &RemoteJWKS{
|
||||||
|
FetchAsynchronously: true,
|
||||||
|
URI: "https://example.com/.well-known/jwks.json",
|
||||||
|
JWKSCluster: &JWKSCluster{
|
||||||
|
DiscoveryType: "FAKE",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "unsupported jwks cluster discovery type: \"FAKE\"",
|
||||||
|
},
|
||||||
|
"invalid jwt-provider - Remote JWKS cluster with both trustedCa and provider instance": {
|
||||||
|
entry: &JWTProviderConfigEntry{
|
||||||
|
Kind: JWTProvider,
|
||||||
|
Name: "okta",
|
||||||
|
JSONWebKeySet: &JSONWebKeySet{
|
||||||
|
Remote: &RemoteJWKS{
|
||||||
|
FetchAsynchronously: true,
|
||||||
|
URI: "https://example.com/.well-known/jwks.json",
|
||||||
|
JWKSCluster: &JWKSCluster{
|
||||||
|
TLSCertificates: &JWKSTLSCertificate{
|
||||||
|
TrustedCA: &JWKSTLSCertTrustedCA{},
|
||||||
|
CaCertificateProviderInstance: &JWKSTLSCertProviderInstance{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "must specify exactly one of: CaCertificateProviderInstance or TrustedCA for JKWS' TLSCertificates",
|
||||||
|
},
|
||||||
|
"invalid jwt-provider - Remote JWKS cluster with multiple trustedCa options": {
|
||||||
|
entry: &JWTProviderConfigEntry{
|
||||||
|
Kind: JWTProvider,
|
||||||
|
Name: "okta",
|
||||||
|
JSONWebKeySet: &JSONWebKeySet{
|
||||||
|
Remote: &RemoteJWKS{
|
||||||
|
FetchAsynchronously: true,
|
||||||
|
URI: "https://example.com/.well-known/jwks.json",
|
||||||
|
JWKSCluster: &JWKSCluster{
|
||||||
|
TLSCertificates: &JWKSTLSCertificate{
|
||||||
|
TrustedCA: &JWKSTLSCertTrustedCA{
|
||||||
|
Filename: "myfile.cert",
|
||||||
|
InlineString: "*****",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "must specify exactly one of: Filename, EnvironmentVariable, InlineString or InlineBytes for JWKS' TrustedCA",
|
||||||
},
|
},
|
||||||
"invalid jwt-provider - JWT location with 2 fields": {
|
"invalid jwt-provider - JWT location with 2 fields": {
|
||||||
entry: &JWTProviderConfigEntry{
|
entry: &JWTProviderConfigEntry{
|
||||||
|
@ -244,7 +301,7 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
validateErr: "Must set exactly one of: JWT location header, query param or cookie",
|
validateErr: "must set exactly one of: JWT location header, query param or cookie",
|
||||||
},
|
},
|
||||||
"valid jwt-provider - with all possible fields": {
|
"valid jwt-provider - with all possible fields": {
|
||||||
entry: &JWTProviderConfigEntry{
|
entry: &JWTProviderConfigEntry{
|
||||||
|
@ -265,6 +322,15 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
MaxInterval: hundredSeconds,
|
MaxInterval: hundredSeconds,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
JWKSCluster: &JWKSCluster{
|
||||||
|
DiscoveryType: "STATIC",
|
||||||
|
ConnectTimeout: connectTimeout,
|
||||||
|
TLSCertificates: &JWKSTLSCertificate{
|
||||||
|
TrustedCA: &JWKSTLSCertTrustedCA{
|
||||||
|
Filename: "myfile.cert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Forwarding: &JWTForwardingConfig{
|
Forwarding: &JWTForwardingConfig{
|
||||||
|
@ -297,6 +363,15 @@ func TestJWTProviderConfigEntry_ValidateAndNormalize(t *testing.T) {
|
||||||
MaxInterval: hundredSeconds,
|
MaxInterval: hundredSeconds,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
JWKSCluster: &JWKSCluster{
|
||||||
|
DiscoveryType: "STATIC",
|
||||||
|
ConnectTimeout: connectTimeout,
|
||||||
|
TLSCertificates: &JWKSTLSCertificate{
|
||||||
|
TrustedCA: &JWKSTLSCertTrustedCA{
|
||||||
|
Filename: "myfile.cert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Forwarding: &JWTForwardingConfig{
|
Forwarding: &JWTForwardingConfig{
|
||||||
|
|
|
@ -211,13 +211,9 @@ func makeJWTProviderCluster(p *structs.JWTProviderConfigEntry) (*envoy_cluster_v
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: expose additional fields: eg. ConnectTimeout, through
|
|
||||||
// JWTProviderConfigEntry to allow user to configure cluster
|
|
||||||
cluster := &envoy_cluster_v3.Cluster{
|
cluster := &envoy_cluster_v3.Cluster{
|
||||||
Name: makeJWKSClusterName(p.Name),
|
Name: makeJWKSClusterName(p.Name),
|
||||||
ClusterDiscoveryType: &envoy_cluster_v3.Cluster_Type{
|
ClusterDiscoveryType: makeJWKSDiscoveryClusterType(p.JSONWebKeySet.Remote),
|
||||||
Type: envoy_cluster_v3.Cluster_STRICT_DNS,
|
|
||||||
},
|
|
||||||
LoadAssignment: &envoy_endpoint_v3.ClusterLoadAssignment{
|
LoadAssignment: &envoy_endpoint_v3.ClusterLoadAssignment{
|
||||||
ClusterName: makeJWKSClusterName(p.Name),
|
ClusterName: makeJWKSClusterName(p.Name),
|
||||||
Endpoints: []*envoy_endpoint_v3.LocalityLbEndpoints{
|
Endpoints: []*envoy_endpoint_v3.LocalityLbEndpoints{
|
||||||
|
@ -230,14 +226,19 @@ func makeJWTProviderCluster(p *structs.JWTProviderConfigEntry) (*envoy_cluster_v
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c := p.JSONWebKeySet.Remote.JWKSCluster; c != nil {
|
||||||
|
connectTimeout := int64(c.ConnectTimeout / time.Second)
|
||||||
|
if connectTimeout > 0 {
|
||||||
|
cluster.ConnectTimeout = &durationpb.Duration{Seconds: connectTimeout}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if scheme == "https" {
|
if scheme == "https" {
|
||||||
// TODO: expose this configuration through JWTProviderConfigEntry to allow
|
|
||||||
// user to configure certs
|
|
||||||
jwksTLSContext, err := makeUpstreamTLSTransportSocket(
|
jwksTLSContext, err := makeUpstreamTLSTransportSocket(
|
||||||
&envoy_tls_v3.UpstreamTlsContext{
|
&envoy_tls_v3.UpstreamTlsContext{
|
||||||
CommonTlsContext: &envoy_tls_v3.CommonTlsContext{
|
CommonTlsContext: &envoy_tls_v3.CommonTlsContext{
|
||||||
ValidationContextType: &envoy_tls_v3.CommonTlsContext_ValidationContext{
|
ValidationContextType: &envoy_tls_v3.CommonTlsContext_ValidationContext{
|
||||||
ValidationContext: &envoy_tls_v3.CertificateValidationContext{},
|
ValidationContext: makeJWTCertValidationContext(p.JSONWebKeySet.Remote.JWKSCluster),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -251,6 +252,76 @@ func makeJWTProviderCluster(p *structs.JWTProviderConfigEntry) (*envoy_cluster_v
|
||||||
return cluster, nil
|
return cluster, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeJWKSDiscoveryClusterType(r *structs.RemoteJWKS) *envoy_cluster_v3.Cluster_Type {
|
||||||
|
ct := &envoy_cluster_v3.Cluster_Type{}
|
||||||
|
if r == nil || r.JWKSCluster == nil {
|
||||||
|
return ct
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.JWKSCluster.DiscoveryType {
|
||||||
|
case structs.DiscoveryTypeStatic:
|
||||||
|
ct.Type = envoy_cluster_v3.Cluster_STATIC
|
||||||
|
case structs.DiscoveryTypeLogicalDNS:
|
||||||
|
ct.Type = envoy_cluster_v3.Cluster_LOGICAL_DNS
|
||||||
|
case structs.DiscoveryTypeEDS:
|
||||||
|
ct.Type = envoy_cluster_v3.Cluster_EDS
|
||||||
|
case structs.DiscoveryTypeOriginalDST:
|
||||||
|
ct.Type = envoy_cluster_v3.Cluster_ORIGINAL_DST
|
||||||
|
case structs.DiscoveryTypeStrictDNS:
|
||||||
|
fallthrough // default case so uses the default option
|
||||||
|
default:
|
||||||
|
ct.Type = envoy_cluster_v3.Cluster_STRICT_DNS
|
||||||
|
}
|
||||||
|
return ct
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeJWTCertValidationContext(p *structs.JWKSCluster) *envoy_tls_v3.CertificateValidationContext {
|
||||||
|
vc := &envoy_tls_v3.CertificateValidationContext{}
|
||||||
|
if p == nil || p.TLSCertificates == nil {
|
||||||
|
return vc
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc := p.TLSCertificates.TrustedCA; tc != nil {
|
||||||
|
vc.TrustedCa = &envoy_core_v3.DataSource{}
|
||||||
|
if tc.Filename != "" {
|
||||||
|
vc.TrustedCa.Specifier = &envoy_core_v3.DataSource_Filename{
|
||||||
|
Filename: tc.Filename,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.EnvironmentVariable != "" {
|
||||||
|
vc.TrustedCa.Specifier = &envoy_core_v3.DataSource_EnvironmentVariable{
|
||||||
|
EnvironmentVariable: tc.EnvironmentVariable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.InlineString != "" {
|
||||||
|
vc.TrustedCa.Specifier = &envoy_core_v3.DataSource_InlineString{
|
||||||
|
InlineString: tc.InlineString,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tc.InlineBytes) > 0 {
|
||||||
|
vc.TrustedCa.Specifier = &envoy_core_v3.DataSource_InlineBytes{
|
||||||
|
InlineBytes: tc.InlineBytes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pi := p.TLSCertificates.CaCertificateProviderInstance; pi != nil {
|
||||||
|
vc.CaCertificateProviderInstance = &envoy_tls_v3.CertificateProviderPluginInstance{}
|
||||||
|
if pi.InstanceName != "" {
|
||||||
|
vc.CaCertificateProviderInstance.InstanceName = pi.InstanceName
|
||||||
|
}
|
||||||
|
|
||||||
|
if pi.CertificateName != "" {
|
||||||
|
vc.CaCertificateProviderInstance.CertificateName = pi.CertificateName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vc
|
||||||
|
}
|
||||||
|
|
||||||
// parseJWTRemoteURL splits the URI into domain, scheme and port.
|
// parseJWTRemoteURL splits the URI into domain, scheme and port.
|
||||||
// It will default to port 80 for http and 443 for https for any
|
// It will default to port 80 for http and 443 for https for any
|
||||||
// URI that does not specify a port.
|
// URI that does not specify a port.
|
||||||
|
|
|
@ -1037,11 +1037,104 @@ func makeTestProviderWithJWKS(uri string) *structs.JWTProviderConfigEntry {
|
||||||
RequestTimeoutMs: 1000,
|
RequestTimeoutMs: 1000,
|
||||||
FetchAsynchronously: true,
|
FetchAsynchronously: true,
|
||||||
URI: uri,
|
URI: uri,
|
||||||
|
JWKSCluster: &structs.JWKSCluster{
|
||||||
|
DiscoveryType: structs.DiscoveryTypeStatic,
|
||||||
|
ConnectTimeout: time.Duration(5) * time.Second,
|
||||||
|
TLSCertificates: &structs.JWKSTLSCertificate{
|
||||||
|
TrustedCA: &structs.JWKSTLSCertTrustedCA{
|
||||||
|
Filename: "mycert.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMakeJWKSDiscoveryClusterType(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
remoteJWKS *structs.RemoteJWKS
|
||||||
|
expectedClusterType *envoy_cluster_v3.Cluster_Type
|
||||||
|
}{
|
||||||
|
"nil remote jwks": {
|
||||||
|
remoteJWKS: nil,
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{},
|
||||||
|
},
|
||||||
|
"nil jwks cluster": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{},
|
||||||
|
},
|
||||||
|
"jwks cluster defaults to Strict DNS": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{
|
||||||
|
JWKSCluster: &structs.JWKSCluster{},
|
||||||
|
},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{
|
||||||
|
Type: envoy_cluster_v3.Cluster_STRICT_DNS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"jwks with cluster EDS": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{
|
||||||
|
JWKSCluster: &structs.JWKSCluster{
|
||||||
|
DiscoveryType: "EDS",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{
|
||||||
|
Type: envoy_cluster_v3.Cluster_EDS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"jwks with static dns": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{
|
||||||
|
JWKSCluster: &structs.JWKSCluster{
|
||||||
|
DiscoveryType: "STATIC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{
|
||||||
|
Type: envoy_cluster_v3.Cluster_STATIC,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"jwks with original dst": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{
|
||||||
|
JWKSCluster: &structs.JWKSCluster{
|
||||||
|
DiscoveryType: "ORIGINAL_DST",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{
|
||||||
|
Type: envoy_cluster_v3.Cluster_ORIGINAL_DST,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"jwks with strict dns": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{
|
||||||
|
JWKSCluster: &structs.JWKSCluster{
|
||||||
|
DiscoveryType: "STRICT_DNS",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{
|
||||||
|
Type: envoy_cluster_v3.Cluster_STRICT_DNS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"jwks with logical dns": {
|
||||||
|
remoteJWKS: &structs.RemoteJWKS{
|
||||||
|
JWKSCluster: &structs.JWKSCluster{
|
||||||
|
DiscoveryType: "LOGICAL_DNS",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedClusterType: &envoy_cluster_v3.Cluster_Type{
|
||||||
|
Type: envoy_cluster_v3.Cluster_LOGICAL_DNS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
clusterType := makeJWKSDiscoveryClusterType(tt.remoteJWKS)
|
||||||
|
|
||||||
|
require.Equal(t, tt.expectedClusterType, clusterType)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseJWTRemoteURL(t *testing.T) {
|
func TestParseJWTRemoteURL(t *testing.T) {
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
uri string
|
uri string
|
||||||
|
|
|
@ -19,5 +19,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"name": "jwks_cluster_okta",
|
"name": "jwks_cluster_okta",
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -19,5 +19,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"name": "jwks_cluster_okta",
|
"name": "jwks_cluster_okta",
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -19,5 +19,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"name": "jwks_cluster_okta",
|
"name": "jwks_cluster_okta",
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -19,5 +19,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"name": "jwks_cluster_okta",
|
"name": "jwks_cluster_okta",
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -24,9 +24,14 @@
|
||||||
"typedConfig": {
|
"typedConfig": {
|
||||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
"commonTlsContext": {
|
"commonTlsContext": {
|
||||||
"validationContext": {}
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"filename": "mycert.crt"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -24,9 +24,14 @@
|
||||||
"typedConfig": {
|
"typedConfig": {
|
||||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
"commonTlsContext": {
|
"commonTlsContext": {
|
||||||
"validationContext": {}
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"filename": "mycert.crt"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -24,9 +24,14 @@
|
||||||
"typedConfig": {
|
"typedConfig": {
|
||||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
"commonTlsContext": {
|
"commonTlsContext": {
|
||||||
"validationContext": {}
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"filename": "mycert.crt"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -24,9 +24,14 @@
|
||||||
"typedConfig": {
|
"typedConfig": {
|
||||||
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
|
||||||
"commonTlsContext": {
|
"commonTlsContext": {
|
||||||
"validationContext": {}
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"filename": "mycert.crt"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "STRICT_DNS"
|
"connectTimeout": "5s",
|
||||||
|
"type": "STATIC"
|
||||||
}
|
}
|
|
@ -7,6 +7,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DiscoveryTypeStrictDNS ClusterDiscoveryType = "STRICT_DNS"
|
||||||
|
DiscoveryTypeStatic ClusterDiscoveryType = "STATIC"
|
||||||
|
DiscoveryTypeLogicalDNS ClusterDiscoveryType = "LOGICAL_DNS"
|
||||||
|
DiscoveryTypeEDS ClusterDiscoveryType = "EDS"
|
||||||
|
DiscoveryTypeOriginalDST ClusterDiscoveryType = "ORIGINAL_DST"
|
||||||
|
)
|
||||||
|
|
||||||
type JWTProviderConfigEntry struct {
|
type JWTProviderConfigEntry struct {
|
||||||
// Kind is the kind of configuration entry and must be "jwt-provider".
|
// Kind is the kind of configuration entry and must be "jwt-provider".
|
||||||
Kind string `json:",omitempty"`
|
Kind string `json:",omitempty"`
|
||||||
|
@ -188,6 +196,71 @@ type RemoteJWKS struct {
|
||||||
//
|
//
|
||||||
// There is no retry by default.
|
// There is no retry by default.
|
||||||
RetryPolicy *JWKSRetryPolicy `json:",omitempty" alias:"retry_policy"`
|
RetryPolicy *JWKSRetryPolicy `json:",omitempty" alias:"retry_policy"`
|
||||||
|
|
||||||
|
// JWKSCluster defines how the specified Remote JWKS URI is to be fetched.
|
||||||
|
JWKSCluster *JWKSCluster `json:",omitempty" alias:"jwks_cluster"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWKSCluster struct {
|
||||||
|
// DiscoveryType refers to the service discovery type to use for resolving the cluster.
|
||||||
|
//
|
||||||
|
// This defaults to STRICT_DNS.
|
||||||
|
// Other options include STATIC, LOGICAL_DNS, EDS or ORIGINAL_DST.
|
||||||
|
DiscoveryType ClusterDiscoveryType `json:",omitempty" alias:"discovery_type"`
|
||||||
|
|
||||||
|
// TLSCertificates refers to the data containing certificate authority certificates to use
|
||||||
|
// in verifying a presented peer certificate.
|
||||||
|
// If not specified and a peer certificate is presented it will not be verified.
|
||||||
|
//
|
||||||
|
// Must be either CaCertificateProviderInstance or TrustedCA.
|
||||||
|
TLSCertificates *JWKSTLSCertificate `json:",omitempty" alias:"tls_certificates"`
|
||||||
|
|
||||||
|
// The timeout for new network connections to hosts in the cluster.
|
||||||
|
// If not set, a default value of 5s will be used.
|
||||||
|
ConnectTimeout time.Duration `json:",omitempty" alias:"connect_timeout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterDiscoveryType string
|
||||||
|
|
||||||
|
// JWKSTLSCertificate refers to the data containing certificate authority certificates to use
|
||||||
|
// in verifying a presented peer certificate.
|
||||||
|
// If not specified and a peer certificate is presented it will not be verified.
|
||||||
|
//
|
||||||
|
// Must be either CaCertificateProviderInstance or TrustedCA.
|
||||||
|
type JWKSTLSCertificate struct {
|
||||||
|
// CaCertificateProviderInstance Certificate provider instance for fetching TLS certificates.
|
||||||
|
CaCertificateProviderInstance *JWKSTLSCertProviderInstance `json:",omitempty" alias:"ca_certificate_provider_instance"`
|
||||||
|
|
||||||
|
// TrustedCA defines TLS certificate data containing certificate authority certificates
|
||||||
|
// to use in verifying a presented peer certificate.
|
||||||
|
//
|
||||||
|
// Exactly one of Filename, EnvironmentVariable, InlineString or InlineBytes must be specified.
|
||||||
|
TrustedCA *JWKSTLSCertTrustedCA `json:",omitempty" alias:"trusted_ca"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JWKSTLSCertTrustedCA defines TLS certificate data containing certificate authority certificates
|
||||||
|
// to use in verifying a presented peer certificate.
|
||||||
|
//
|
||||||
|
// Exactly one of Filename, EnvironmentVariable, InlineString or InlineBytes must be specified.
|
||||||
|
type JWKSTLSCertTrustedCA struct {
|
||||||
|
Filename string `json:",omitempty" alias:"filename"`
|
||||||
|
EnvironmentVariable string `json:",omitempty" alias:"environment_variable"`
|
||||||
|
InlineString string `json:",omitempty" alias:"inline_string"`
|
||||||
|
InlineBytes []byte `json:",omitempty" alias:"inline_bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWKSTLSCertProviderInstance struct {
|
||||||
|
// InstanceName refers to the certificate provider instance name
|
||||||
|
//
|
||||||
|
// The default value is "default".
|
||||||
|
InstanceName string `json:",omitempty" alias:"instance_name"`
|
||||||
|
|
||||||
|
// CertificateName is used to specify certificate instances or types. For example, "ROOTCA" to specify
|
||||||
|
// a root-certificate (validation context) or "example.com" to specify a certificate for a
|
||||||
|
// particular domain.
|
||||||
|
//
|
||||||
|
// The default value is the empty string.
|
||||||
|
CertificateName string `json:",omitempty" alias:"certificate_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type JWKSRetryPolicy struct {
|
type JWKSRetryPolicy struct {
|
||||||
|
|
|
@ -4,6 +4,7 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/sdk/testutil"
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -17,12 +18,23 @@ func TestAPI_ConfigEntries_JWTProvider(t *testing.T) {
|
||||||
entries := c.ConfigEntries()
|
entries := c.ConfigEntries()
|
||||||
|
|
||||||
testutil.RunStep(t, "set and get", func(t *testing.T) {
|
testutil.RunStep(t, "set and get", func(t *testing.T) {
|
||||||
|
connectTimeout := time.Duration(5) * time.Second
|
||||||
jwtProvider := &JWTProviderConfigEntry{
|
jwtProvider := &JWTProviderConfigEntry{
|
||||||
Name: "okta",
|
Name: "okta",
|
||||||
Kind: JWTProvider,
|
Kind: JWTProvider,
|
||||||
JSONWebKeySet: &JSONWebKeySet{
|
JSONWebKeySet: &JSONWebKeySet{
|
||||||
Local: &LocalJWKS{
|
Remote: &RemoteJWKS{
|
||||||
Filename: "test.txt",
|
FetchAsynchronously: true,
|
||||||
|
URI: "https://example.com/.well-known/jwks.json",
|
||||||
|
JWKSCluster: &JWKSCluster{
|
||||||
|
DiscoveryType: "STATIC",
|
||||||
|
ConnectTimeout: connectTimeout,
|
||||||
|
TLSCertificates: &JWKSTLSCertificate{
|
||||||
|
TrustedCA: &JWKSTLSCertTrustedCA{
|
||||||
|
Filename: "myfile.cert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Meta: map[string]string{
|
Meta: map[string]string{
|
||||||
|
|
|
@ -1082,6 +1082,30 @@ func JSONWebKeySetFromStructs(t *structs.JSONWebKeySet, s *JSONWebKeySet) {
|
||||||
s.Remote = &x
|
s.Remote = &x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func JWKSClusterToStructs(s *JWKSCluster, t *structs.JWKSCluster) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.DiscoveryType = structs.ClusterDiscoveryType(s.DiscoveryType)
|
||||||
|
if s.TLSCertificates != nil {
|
||||||
|
var x structs.JWKSTLSCertificate
|
||||||
|
JWKSTLSCertificateToStructs(s.TLSCertificates, &x)
|
||||||
|
t.TLSCertificates = &x
|
||||||
|
}
|
||||||
|
t.ConnectTimeout = structs.DurationFromProto(s.ConnectTimeout)
|
||||||
|
}
|
||||||
|
func JWKSClusterFromStructs(t *structs.JWKSCluster, s *JWKSCluster) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.DiscoveryType = string(t.DiscoveryType)
|
||||||
|
if t.TLSCertificates != nil {
|
||||||
|
var x JWKSTLSCertificate
|
||||||
|
JWKSTLSCertificateFromStructs(t.TLSCertificates, &x)
|
||||||
|
s.TLSCertificates = &x
|
||||||
|
}
|
||||||
|
s.ConnectTimeout = structs.DurationToProto(t.ConnectTimeout)
|
||||||
|
}
|
||||||
func JWKSRetryPolicyToStructs(s *JWKSRetryPolicy, t *structs.JWKSRetryPolicy) {
|
func JWKSRetryPolicyToStructs(s *JWKSRetryPolicy, t *structs.JWKSRetryPolicy) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return
|
return
|
||||||
|
@ -1104,6 +1128,68 @@ func JWKSRetryPolicyFromStructs(t *structs.JWKSRetryPolicy, s *JWKSRetryPolicy)
|
||||||
s.RetryPolicyBackOff = &x
|
s.RetryPolicyBackOff = &x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func JWKSTLSCertProviderInstanceToStructs(s *JWKSTLSCertProviderInstance, t *structs.JWKSTLSCertProviderInstance) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.InstanceName = s.InstanceName
|
||||||
|
t.CertificateName = s.CertificateName
|
||||||
|
}
|
||||||
|
func JWKSTLSCertProviderInstanceFromStructs(t *structs.JWKSTLSCertProviderInstance, s *JWKSTLSCertProviderInstance) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.InstanceName = t.InstanceName
|
||||||
|
s.CertificateName = t.CertificateName
|
||||||
|
}
|
||||||
|
func JWKSTLSCertTrustedCAToStructs(s *JWKSTLSCertTrustedCA, t *structs.JWKSTLSCertTrustedCA) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Filename = s.Filename
|
||||||
|
t.EnvironmentVariable = s.EnvironmentVariable
|
||||||
|
t.InlineString = s.InlineString
|
||||||
|
t.InlineBytes = s.InlineBytes
|
||||||
|
}
|
||||||
|
func JWKSTLSCertTrustedCAFromStructs(t *structs.JWKSTLSCertTrustedCA, s *JWKSTLSCertTrustedCA) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.Filename = t.Filename
|
||||||
|
s.EnvironmentVariable = t.EnvironmentVariable
|
||||||
|
s.InlineString = t.InlineString
|
||||||
|
s.InlineBytes = t.InlineBytes
|
||||||
|
}
|
||||||
|
func JWKSTLSCertificateToStructs(s *JWKSTLSCertificate, t *structs.JWKSTLSCertificate) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.CaCertificateProviderInstance != nil {
|
||||||
|
var x structs.JWKSTLSCertProviderInstance
|
||||||
|
JWKSTLSCertProviderInstanceToStructs(s.CaCertificateProviderInstance, &x)
|
||||||
|
t.CaCertificateProviderInstance = &x
|
||||||
|
}
|
||||||
|
if s.TrustedCA != nil {
|
||||||
|
var x structs.JWKSTLSCertTrustedCA
|
||||||
|
JWKSTLSCertTrustedCAToStructs(s.TrustedCA, &x)
|
||||||
|
t.TrustedCA = &x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func JWKSTLSCertificateFromStructs(t *structs.JWKSTLSCertificate, s *JWKSTLSCertificate) {
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if t.CaCertificateProviderInstance != nil {
|
||||||
|
var x JWKSTLSCertProviderInstance
|
||||||
|
JWKSTLSCertProviderInstanceFromStructs(t.CaCertificateProviderInstance, &x)
|
||||||
|
s.CaCertificateProviderInstance = &x
|
||||||
|
}
|
||||||
|
if t.TrustedCA != nil {
|
||||||
|
var x JWKSTLSCertTrustedCA
|
||||||
|
JWKSTLSCertTrustedCAFromStructs(t.TrustedCA, &x)
|
||||||
|
s.TrustedCA = &x
|
||||||
|
}
|
||||||
|
}
|
||||||
func JWTCacheConfigToStructs(s *JWTCacheConfig, t *structs.JWTCacheConfig) {
|
func JWTCacheConfigToStructs(s *JWTCacheConfig, t *structs.JWTCacheConfig) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return
|
return
|
||||||
|
@ -1521,6 +1607,11 @@ func RemoteJWKSToStructs(s *RemoteJWKS, t *structs.RemoteJWKS) {
|
||||||
JWKSRetryPolicyToStructs(s.RetryPolicy, &x)
|
JWKSRetryPolicyToStructs(s.RetryPolicy, &x)
|
||||||
t.RetryPolicy = &x
|
t.RetryPolicy = &x
|
||||||
}
|
}
|
||||||
|
if s.JWKSCluster != nil {
|
||||||
|
var x structs.JWKSCluster
|
||||||
|
JWKSClusterToStructs(s.JWKSCluster, &x)
|
||||||
|
t.JWKSCluster = &x
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func RemoteJWKSFromStructs(t *structs.RemoteJWKS, s *RemoteJWKS) {
|
func RemoteJWKSFromStructs(t *structs.RemoteJWKS, s *RemoteJWKS) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
|
@ -1535,6 +1626,11 @@ func RemoteJWKSFromStructs(t *structs.RemoteJWKS, s *RemoteJWKS) {
|
||||||
JWKSRetryPolicyFromStructs(t.RetryPolicy, &x)
|
JWKSRetryPolicyFromStructs(t.RetryPolicy, &x)
|
||||||
s.RetryPolicy = &x
|
s.RetryPolicy = &x
|
||||||
}
|
}
|
||||||
|
if t.JWKSCluster != nil {
|
||||||
|
var x JWKSCluster
|
||||||
|
JWKSClusterFromStructs(t.JWKSCluster, &x)
|
||||||
|
s.JWKSCluster = &x
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func ResourceReferenceToStructs(s *ResourceReference, t *structs.ResourceReference) {
|
func ResourceReferenceToStructs(s *ResourceReference, t *structs.ResourceReference) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
|
|
|
@ -727,6 +727,46 @@ func (msg *RemoteJWKS) UnmarshalBinary(b []byte) error {
|
||||||
return proto.Unmarshal(b, msg)
|
return proto.Unmarshal(b, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler
|
||||||
|
func (msg *JWKSCluster) MarshalBinary() ([]byte, error) {
|
||||||
|
return proto.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||||
|
func (msg *JWKSCluster) UnmarshalBinary(b []byte) error {
|
||||||
|
return proto.Unmarshal(b, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler
|
||||||
|
func (msg *JWKSTLSCertificate) MarshalBinary() ([]byte, error) {
|
||||||
|
return proto.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||||
|
func (msg *JWKSTLSCertificate) UnmarshalBinary(b []byte) error {
|
||||||
|
return proto.Unmarshal(b, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler
|
||||||
|
func (msg *JWKSTLSCertProviderInstance) MarshalBinary() ([]byte, error) {
|
||||||
|
return proto.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||||
|
func (msg *JWKSTLSCertProviderInstance) UnmarshalBinary(b []byte) error {
|
||||||
|
return proto.Unmarshal(b, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler
|
||||||
|
func (msg *JWKSTLSCertTrustedCA) MarshalBinary() ([]byte, error) {
|
||||||
|
return proto.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||||
|
func (msg *JWKSTLSCertTrustedCA) UnmarshalBinary(b []byte) error {
|
||||||
|
return proto.Unmarshal(b, msg)
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalBinary implements encoding.BinaryMarshaler
|
// MarshalBinary implements encoding.BinaryMarshaler
|
||||||
func (msg *JWKSRetryPolicy) MarshalBinary() ([]byte, error) {
|
func (msg *JWKSRetryPolicy) MarshalBinary() ([]byte, error) {
|
||||||
return proto.Marshal(msg)
|
return proto.Marshal(msg)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1021,6 +1021,51 @@ message RemoteJWKS {
|
||||||
google.protobuf.Duration CacheDuration = 3;
|
google.protobuf.Duration CacheDuration = 3;
|
||||||
bool FetchAsynchronously = 4;
|
bool FetchAsynchronously = 4;
|
||||||
JWKSRetryPolicy RetryPolicy = 5;
|
JWKSRetryPolicy RetryPolicy = 5;
|
||||||
|
JWKSCluster JWKSCluster = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mog annotation:
|
||||||
|
//
|
||||||
|
// target=github.com/hashicorp/consul/agent/structs.JWKSCluster
|
||||||
|
// output=config_entry.gen.go
|
||||||
|
// name=Structs
|
||||||
|
message JWKSCluster {
|
||||||
|
string DiscoveryType = 1;
|
||||||
|
JWKSTLSCertificate TLSCertificates = 2;
|
||||||
|
// mog: func-to=structs.DurationFromProto func-from=structs.DurationToProto
|
||||||
|
google.protobuf.Duration ConnectTimeout = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mog annotation:
|
||||||
|
//
|
||||||
|
// target=github.com/hashicorp/consul/agent/structs.JWKSTLSCertificate
|
||||||
|
// output=config_entry.gen.go
|
||||||
|
// name=Structs
|
||||||
|
message JWKSTLSCertificate {
|
||||||
|
JWKSTLSCertProviderInstance CaCertificateProviderInstance = 1;
|
||||||
|
JWKSTLSCertTrustedCA TrustedCA = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mog annotation:
|
||||||
|
//
|
||||||
|
// target=github.com/hashicorp/consul/agent/structs.JWKSTLSCertProviderInstance
|
||||||
|
// output=config_entry.gen.go
|
||||||
|
// name=Structs
|
||||||
|
message JWKSTLSCertProviderInstance {
|
||||||
|
string InstanceName = 1;
|
||||||
|
string CertificateName = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mog annotation:
|
||||||
|
//
|
||||||
|
// target=github.com/hashicorp/consul/agent/structs.JWKSTLSCertTrustedCA
|
||||||
|
// output=config_entry.gen.go
|
||||||
|
// name=Structs
|
||||||
|
message JWKSTLSCertTrustedCA {
|
||||||
|
string Filename = 1;
|
||||||
|
string EnvironmentVariable = 2;
|
||||||
|
string InlineString = 3;
|
||||||
|
bytes InlineBytes = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mog annotation:
|
// mog annotation:
|
||||||
|
|
Loading…
Reference in New Issue