Read the names of the impersonation-related resources from the config
They were previously temporarily hardcoded. Now they are set at deploy time via the static ConfigMap in deployment.yaml
This commit is contained in:
parent
41140766f0
commit
a75c2194bc
@ -42,6 +42,10 @@ data:
|
|||||||
servingCertificateSecret: (@= defaultResourceNameWithSuffix("api-tls-serving-certificate") @)
|
servingCertificateSecret: (@= defaultResourceNameWithSuffix("api-tls-serving-certificate") @)
|
||||||
credentialIssuer: (@= defaultResourceNameWithSuffix("config") @)
|
credentialIssuer: (@= defaultResourceNameWithSuffix("config") @)
|
||||||
apiService: (@= defaultResourceNameWithSuffix("api") @)
|
apiService: (@= defaultResourceNameWithSuffix("api") @)
|
||||||
|
impersonationConfigMap: (@= defaultResourceNameWithSuffix("impersonation-proxy-config") @)
|
||||||
|
impersonationLoadBalancerService: (@= defaultResourceNameWithSuffix("impersonation-proxy-load-balancer") @)
|
||||||
|
impersonationTLSCertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-tls-serving-certificate") @)
|
||||||
|
impersonationCACertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-ca-certificate") @)
|
||||||
labels: (@= json.encode(labels()).rstrip() @)
|
labels: (@= json.encode(labels()).rstrip() @)
|
||||||
kubeCertAgent:
|
kubeCertAgent:
|
||||||
namePrefix: (@= defaultResourceNameWithSuffix("kube-cert-agent-") @)
|
namePrefix: (@= defaultResourceNameWithSuffix("kube-cert-agent-") @)
|
||||||
|
@ -96,8 +96,8 @@ func maybeSetKubeCertAgentDefaults(cfg *KubeCertAgentSpec) {
|
|||||||
func validateNames(names *NamesConfigSpec) error {
|
func validateNames(names *NamesConfigSpec) error {
|
||||||
missingNames := []string{}
|
missingNames := []string{}
|
||||||
if names == nil {
|
if names == nil {
|
||||||
missingNames = append(missingNames, "servingCertificateSecret", "credentialIssuer", "apiService")
|
names = &NamesConfigSpec{}
|
||||||
} else {
|
}
|
||||||
if names.ServingCertificateSecret == "" {
|
if names.ServingCertificateSecret == "" {
|
||||||
missingNames = append(missingNames, "servingCertificateSecret")
|
missingNames = append(missingNames, "servingCertificateSecret")
|
||||||
}
|
}
|
||||||
@ -107,6 +107,17 @@ func validateNames(names *NamesConfigSpec) error {
|
|||||||
if names.APIService == "" {
|
if names.APIService == "" {
|
||||||
missingNames = append(missingNames, "apiService")
|
missingNames = append(missingNames, "apiService")
|
||||||
}
|
}
|
||||||
|
if names.ImpersonationConfigMap == "" {
|
||||||
|
missingNames = append(missingNames, "impersonationConfigMap")
|
||||||
|
}
|
||||||
|
if names.ImpersonationLoadBalancerService == "" {
|
||||||
|
missingNames = append(missingNames, "impersonationLoadBalancerService")
|
||||||
|
}
|
||||||
|
if names.ImpersonationTLSCertificateSecret == "" {
|
||||||
|
missingNames = append(missingNames, "impersonationTLSCertificateSecret")
|
||||||
|
}
|
||||||
|
if names.ImpersonationCACertificateSecret == "" {
|
||||||
|
missingNames = append(missingNames, "impersonationCACertificateSecret")
|
||||||
}
|
}
|
||||||
if len(missingNames) > 0 {
|
if len(missingNames) > 0 {
|
||||||
return constable.Error("missing required names: " + strings.Join(missingNames, ", "))
|
return constable.Error("missing required names: " + strings.Join(missingNames, ", "))
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"go.pinniped.dev/internal/here"
|
"go.pinniped.dev/internal/here"
|
||||||
|
"go.pinniped.dev/internal/plog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFromPath(t *testing.T) {
|
func TestFromPath(t *testing.T) {
|
||||||
@ -21,7 +22,7 @@ func TestFromPath(t *testing.T) {
|
|||||||
wantError string
|
wantError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Happy",
|
name: "Fully filled out",
|
||||||
yaml: here.Doc(`
|
yaml: here.Doc(`
|
||||||
---
|
---
|
||||||
discovery:
|
discovery:
|
||||||
@ -36,13 +37,18 @@ func TestFromPath(t *testing.T) {
|
|||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
kubeCertAgentPrefix: kube-cert-agent-prefix
|
kubeCertAgentPrefix: kube-cert-agent-prefix
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
labels:
|
labels:
|
||||||
myLabelKey1: myLabelValue1
|
myLabelKey1: myLabelValue1
|
||||||
myLabelKey2: myLabelValue2
|
myLabelKey2: myLabelValue2
|
||||||
KubeCertAgent:
|
kubeCertAgent:
|
||||||
namePrefix: kube-cert-agent-name-prefix-
|
namePrefix: kube-cert-agent-name-prefix-
|
||||||
image: kube-cert-agent-image
|
image: kube-cert-agent-image
|
||||||
imagePullSecrets: [kube-cert-agent-image-pull-secret]
|
imagePullSecrets: [kube-cert-agent-image-pull-secret]
|
||||||
|
logLevel: debug
|
||||||
`),
|
`),
|
||||||
wantConfig: &Config{
|
wantConfig: &Config{
|
||||||
DiscoveryInfo: DiscoveryInfoSpec{
|
DiscoveryInfo: DiscoveryInfoSpec{
|
||||||
@ -59,6 +65,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
||||||
CredentialIssuer: "pinniped-config",
|
CredentialIssuer: "pinniped-config",
|
||||||
APIService: "pinniped-api",
|
APIService: "pinniped-api",
|
||||||
|
ImpersonationConfigMap: "impersonationConfigMap-value",
|
||||||
|
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
|
||||||
|
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
|
||||||
|
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||||
},
|
},
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"myLabelKey1": "myLabelValue1",
|
"myLabelKey1": "myLabelValue1",
|
||||||
@ -69,6 +79,7 @@ func TestFromPath(t *testing.T) {
|
|||||||
Image: stringPtr("kube-cert-agent-image"),
|
Image: stringPtr("kube-cert-agent-image"),
|
||||||
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
|
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
|
||||||
},
|
},
|
||||||
|
LogLevel: plog.LevelDebug,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -79,6 +90,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantConfig: &Config{
|
wantConfig: &Config{
|
||||||
DiscoveryInfo: DiscoveryInfoSpec{
|
DiscoveryInfo: DiscoveryInfoSpec{
|
||||||
@ -95,6 +110,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
||||||
CredentialIssuer: "pinniped-config",
|
CredentialIssuer: "pinniped-config",
|
||||||
APIService: "pinniped-api",
|
APIService: "pinniped-api",
|
||||||
|
ImpersonationConfigMap: "impersonationConfigMap-value",
|
||||||
|
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
|
||||||
|
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
|
||||||
|
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||||
},
|
},
|
||||||
Labels: map[string]string{},
|
Labels: map[string]string{},
|
||||||
KubeCertAgentConfig: KubeCertAgentSpec{
|
KubeCertAgentConfig: KubeCertAgentSpec{
|
||||||
@ -106,7 +125,9 @@ func TestFromPath(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Empty",
|
name: "Empty",
|
||||||
yaml: here.Doc(``),
|
yaml: here.Doc(``),
|
||||||
wantError: "validate names: missing required names: servingCertificateSecret, credentialIssuer, apiService",
|
wantError: "validate names: missing required names: servingCertificateSecret, credentialIssuer, " +
|
||||||
|
"apiService, impersonationConfigMap, impersonationLoadBalancerService, " +
|
||||||
|
"impersonationTLSCertificateSecret, impersonationCACertificateSecret",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Missing apiService name",
|
name: "Missing apiService name",
|
||||||
@ -115,6 +136,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
names:
|
names:
|
||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate names: missing required names: apiService",
|
wantError: "validate names: missing required names: apiService",
|
||||||
},
|
},
|
||||||
@ -125,6 +150,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
names:
|
names:
|
||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate names: missing required names: credentialIssuer",
|
wantError: "validate names: missing required names: credentialIssuer",
|
||||||
},
|
},
|
||||||
@ -135,9 +164,82 @@ func TestFromPath(t *testing.T) {
|
|||||||
names:
|
names:
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate names: missing required names: servingCertificateSecret",
|
wantError: "validate names: missing required names: servingCertificateSecret",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Missing impersonationConfigMap name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
|
credentialIssuer: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: impersonationConfigMap",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing impersonationLoadBalancerService name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
|
credentialIssuer: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: impersonationLoadBalancerService",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing impersonationTLSCertificateSecret name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
|
credentialIssuer: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: impersonationTLSCertificateSecret",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing impersonationCACertificateSecret name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
|
credentialIssuer: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: impersonationCACertificateSecret",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing several required names",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
|
credentialIssuer: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: impersonationConfigMap, " +
|
||||||
|
"impersonationTLSCertificateSecret, impersonationCACertificateSecret",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "InvalidDurationRenewBefore",
|
name: "InvalidDurationRenewBefore",
|
||||||
yaml: here.Doc(`
|
yaml: here.Doc(`
|
||||||
@ -150,6 +252,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate api: durationSeconds cannot be smaller than renewBeforeSeconds",
|
wantError: "validate api: durationSeconds cannot be smaller than renewBeforeSeconds",
|
||||||
},
|
},
|
||||||
@ -165,6 +271,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate api: renewBefore must be positive",
|
wantError: "validate api: renewBefore must be positive",
|
||||||
},
|
},
|
||||||
@ -180,6 +290,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate api: renewBefore must be positive",
|
wantError: "validate api: renewBefore must be positive",
|
||||||
},
|
},
|
||||||
@ -196,6 +310,10 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
|
impersonationConfigMap: impersonationConfigMap-value
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate apiGroupSuffix: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')",
|
wantError: "validate apiGroupSuffix: a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')",
|
||||||
},
|
},
|
||||||
|
@ -36,6 +36,10 @@ type NamesConfigSpec struct {
|
|||||||
ServingCertificateSecret string `json:"servingCertificateSecret"`
|
ServingCertificateSecret string `json:"servingCertificateSecret"`
|
||||||
CredentialIssuer string `json:"credentialIssuer"`
|
CredentialIssuer string `json:"credentialIssuer"`
|
||||||
APIService string `json:"apiService"`
|
APIService string `json:"apiService"`
|
||||||
|
ImpersonationConfigMap string `json:"impersonationConfigMap"`
|
||||||
|
ImpersonationLoadBalancerService string `json:"impersonationLoadBalancerService"`
|
||||||
|
ImpersonationTLSCertificateSecret string `json:"impersonationTLSCertificateSecret"`
|
||||||
|
ImpersonationCACertificateSecret string `json:"impersonationCACertificateSecret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServingCertificateConfigSpec contains the configuration knobs for the API's
|
// ServingCertificateConfigSpec contains the configuration knobs for the API's
|
||||||
|
@ -292,20 +292,24 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
|
|||||||
WithController(
|
WithController(
|
||||||
impersonatorconfig.NewImpersonatorConfigController(
|
impersonatorconfig.NewImpersonatorConfigController(
|
||||||
c.ServerInstallationInfo.Namespace,
|
c.ServerInstallationInfo.Namespace,
|
||||||
"pinniped-concierge-impersonation-proxy-config", // TODO this string should come from `c.NamesConfig`
|
c.NamesConfig.ImpersonationConfigMap,
|
||||||
client.Kubernetes,
|
client.Kubernetes,
|
||||||
informers.installationNamespaceK8s.Core().V1().ConfigMaps(),
|
informers.installationNamespaceK8s.Core().V1().ConfigMaps(),
|
||||||
informers.installationNamespaceK8s.Core().V1().Services(),
|
informers.installationNamespaceK8s.Core().V1().Services(),
|
||||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
controllerlib.WithInitialEvent,
|
controllerlib.WithInitialEvent,
|
||||||
"pinniped-concierge-impersonation-proxy-load-balancer", // TODO this string should come from `c.NamesConfig`
|
c.NamesConfig.ImpersonationLoadBalancerService,
|
||||||
"pinniped-concierge-impersonation-proxy-tls-serving-certificate", // TODO this string should come from `c.NamesConfig`
|
c.NamesConfig.ImpersonationTLSCertificateSecret,
|
||||||
"pinniped-concierge-impersonation-proxy-ca-certificate", // TODO this string should come from `c.NamesConfig`
|
c.NamesConfig.ImpersonationCACertificateSecret,
|
||||||
c.Labels,
|
c.Labels,
|
||||||
tls.Listen,
|
tls.Listen,
|
||||||
func() (http.Handler, error) {
|
func() (http.Handler, error) {
|
||||||
impersonationProxyHandler, err := impersonator.New(c.AuthenticatorCache, c.LoginJSONDecoder, klogr.New().WithName("impersonation-proxy"))
|
impersonationProxyHandler, err := impersonator.New(
|
||||||
|
c.AuthenticatorCache,
|
||||||
|
c.LoginJSONDecoder,
|
||||||
|
klogr.New().WithName("impersonation-proxy"),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create impersonation proxy: %w", err)
|
return nil, fmt.Errorf("could not create impersonation proxy: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,6 @@ import (
|
|||||||
"go.pinniped.dev/test/library"
|
"go.pinniped.dev/test/library"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// TODO don't hard code "pinniped-concierge-" in these strings. It should be constructed from the env app name.
|
|
||||||
impersonationProxyConfigMapName = "pinniped-concierge-impersonation-proxy-config"
|
|
||||||
impersonationProxyTLSSecretName = "pinniped-concierge-impersonation-proxy-tls-serving-certificate" //nolint:gosec // this is not a credential
|
|
||||||
impersonationProxyCASecretName = "pinniped-concierge-impersonation-proxy-ca-certificate" //nolint:gosec // this is not a credential
|
|
||||||
impersonationProxyLoadBalancerName = "pinniped-concierge-impersonation-proxy-load-balancer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Note that this test supports being run on all of our integration test cluster types:
|
// Note that this test supports being run on all of our integration test cluster types:
|
||||||
// - load balancers not supported, has squid proxy (e.g. kind)
|
// - load balancers not supported, has squid proxy (e.g. kind)
|
||||||
// - load balancers supported, has squid proxy (e.g. EKS)
|
// - load balancers supported, has squid proxy (e.g. EKS)
|
||||||
@ -94,11 +86,11 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
return impersonationProxyClient
|
return impersonationProxyClient
|
||||||
}
|
}
|
||||||
|
|
||||||
oldConfigMap, err := adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Get(ctx, impersonationProxyConfigMapName, metav1.GetOptions{})
|
oldConfigMap, err := adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Get(ctx, impersonationProxyConfigMapName(env), metav1.GetOptions{})
|
||||||
if !k8serrors.IsNotFound(err) {
|
if !k8serrors.IsNotFound(err) {
|
||||||
require.NoError(t, err) // other errors aside from NotFound are unexpected
|
require.NoError(t, err) // other errors aside from NotFound are unexpected
|
||||||
t.Logf("stashing a pre-existing configmap %s", oldConfigMap.Name)
|
t.Logf("stashing a pre-existing configmap %s", oldConfigMap.Name)
|
||||||
require.NoError(t, adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Delete(ctx, impersonationProxyConfigMapName, metav1.DeleteOptions{}))
|
require.NoError(t, adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Delete(ctx, impersonationProxyConfigMapName(env), metav1.DeleteOptions{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
impersonationProxyLoadBalancerIngress := ""
|
impersonationProxyLoadBalancerIngress := ""
|
||||||
@ -106,13 +98,14 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
if env.HasCapability(library.HasExternalLoadBalancerProvider) { //nolint:nestif // come on... it's just a test
|
if env.HasCapability(library.HasExternalLoadBalancerProvider) { //nolint:nestif // come on... it's just a test
|
||||||
// Check that load balancer has been created.
|
// Check that load balancer has been created.
|
||||||
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
||||||
return hasImpersonationProxyLoadBalancerService(ctx, adminClient, env.ConciergeNamespace)
|
return hasImpersonationProxyLoadBalancerService(ctx, env, adminClient)
|
||||||
}, 10*time.Second, 500*time.Millisecond)
|
}, 10*time.Second, 500*time.Millisecond)
|
||||||
|
|
||||||
|
// TODO this information should come from the CredentialIssuer status once that is implemented
|
||||||
// Wait for the load balancer to get an ingress and make a note of its address.
|
// Wait for the load balancer to get an ingress and make a note of its address.
|
||||||
var ingress *corev1.LoadBalancerIngress
|
var ingress *corev1.LoadBalancerIngress
|
||||||
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
||||||
ingress, err = getImpersonationProxyLoadBalancerIngress(ctx, adminClient, env.ConciergeNamespace)
|
ingress, err = getImpersonationProxyLoadBalancerIngress(ctx, env, adminClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -131,7 +124,7 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
|
|
||||||
// Check that no load balancer has been created.
|
// Check that no load balancer has been created.
|
||||||
library.RequireNeverWithoutError(t, func() (bool, error) {
|
library.RequireNeverWithoutError(t, func() (bool, error) {
|
||||||
return hasImpersonationProxyLoadBalancerService(ctx, adminClient, env.ConciergeNamespace)
|
return hasImpersonationProxyLoadBalancerService(ctx, env, adminClient)
|
||||||
}, 10*time.Second, 500*time.Millisecond)
|
}, 10*time.Second, 500*time.Millisecond)
|
||||||
|
|
||||||
// Check that we can't use the impersonation proxy to execute kubectl commands yet.
|
// Check that we can't use the impersonation proxy to execute kubectl commands yet.
|
||||||
@ -139,7 +132,7 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
require.EqualError(t, err, serviceUnavailableViaSquidError)
|
require.EqualError(t, err, serviceUnavailableViaSquidError)
|
||||||
|
|
||||||
// Create configuration to make the impersonation proxy turn on with a hard coded endpoint (without a LoadBalancer).
|
// Create configuration to make the impersonation proxy turn on with a hard coded endpoint (without a LoadBalancer).
|
||||||
configMap := configMapForConfig(t, impersonator.Config{
|
configMap := configMapForConfig(t, env, impersonator.Config{
|
||||||
Mode: impersonator.ModeEnabled,
|
Mode: impersonator.ModeEnabled,
|
||||||
Endpoint: proxyServiceEndpoint,
|
Endpoint: proxyServiceEndpoint,
|
||||||
TLS: nil,
|
TLS: nil,
|
||||||
@ -152,8 +145,8 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
t.Logf("cleaning up configmap at end of test %s", impersonationProxyConfigMapName)
|
t.Logf("cleaning up configmap at end of test %s", impersonationProxyConfigMapName(env))
|
||||||
err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Delete(ctx, impersonationProxyConfigMapName, metav1.DeleteOptions{})
|
err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Delete(ctx, impersonationProxyConfigMapName(env), metav1.DeleteOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if len(oldConfigMap.Data) != 0 {
|
if len(oldConfigMap.Data) != 0 {
|
||||||
@ -171,7 +164,7 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
// TODO We should be getting the CA data from the CredentialIssuer's status instead, once that is implemented.
|
// TODO We should be getting the CA data from the CredentialIssuer's status instead, once that is implemented.
|
||||||
var caSecret *corev1.Secret
|
var caSecret *corev1.Secret
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
caSecret, err = adminClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyCASecretName, metav1.GetOptions{})
|
caSecret, err = adminClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyCASecretName(env), metav1.GetOptions{})
|
||||||
return err == nil && caSecret != nil && caSecret.Data["ca.crt"] != nil
|
return err == nil && caSecret != nil && caSecret.Data["ca.crt"] != nil
|
||||||
}, 10*time.Second, 250*time.Millisecond)
|
}, 10*time.Second, 250*time.Millisecond)
|
||||||
impersonationProxyCACertPEM := caSecret.Data["ca.crt"]
|
impersonationProxyCACertPEM := caSecret.Data["ca.crt"]
|
||||||
@ -180,7 +173,7 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
// This could take a while if we are waiting for the load balancer to get an IP or hostname assigned to it, and it
|
// This could take a while if we are waiting for the load balancer to get an IP or hostname assigned to it, and it
|
||||||
// should be fast when we are not waiting for a load balancer (e.g. on kind).
|
// should be fast when we are not waiting for a load balancer (e.g. on kind).
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
_, err = adminClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName, metav1.GetOptions{})
|
_, err = adminClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName(env), metav1.GetOptions{})
|
||||||
return err == nil
|
return err == nil
|
||||||
}, 5*time.Minute, 250*time.Millisecond)
|
}, 5*time.Minute, 250*time.Millisecond)
|
||||||
|
|
||||||
@ -209,7 +202,7 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
|
|
||||||
// Try more Kube API verbs through the impersonation proxy.
|
// Try more Kube API verbs through the impersonation proxy.
|
||||||
t.Run("watching all the basic verbs", func(t *testing.T) {
|
t.Run("watching all the basic verbs", func(t *testing.T) {
|
||||||
// Create a namespace, because it will be easier to exercise deletecollection if we have a namespace.
|
// Create a namespace, because it will be easier to exercise "deletecollection" if we have a namespace.
|
||||||
namespace, err := adminClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
|
namespace, err := adminClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
|
||||||
ObjectMeta: metav1.ObjectMeta{GenerateName: "impersonation-integration-test-"},
|
ObjectMeta: metav1.ObjectMeta{GenerateName: "impersonation-integration-test-"},
|
||||||
}, metav1.CreateOptions{})
|
}, metav1.CreateOptions{})
|
||||||
@ -369,19 +362,19 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
|
|
||||||
// We already know that this Secret exists because we checked above. Now see that we can get it through
|
// We already know that this Secret exists because we checked above. Now see that we can get it through
|
||||||
// the impersonation proxy without any impersonation headers on the request.
|
// the impersonation proxy without any impersonation headers on the request.
|
||||||
_, err = impersonationProxyClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName, metav1.GetOptions{})
|
_, err = impersonationProxyClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName(env), metav1.GetOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Now we'll see what happens when we add an impersonation header to the request. This should generate a
|
// Now we'll see what happens when we add an impersonation header to the request. This should generate a
|
||||||
// request similar to the one above, except that it will have an impersonation header.
|
// request similar to the one above, except that it will have an impersonation header.
|
||||||
_, err = doubleImpersonationClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName, metav1.GetOptions{})
|
_, err = doubleImpersonationClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName(env), metav1.GetOptions{})
|
||||||
// Double impersonation is not supported yet, so we should get an error.
|
// Double impersonation is not supported yet, so we should get an error.
|
||||||
expectedErr := fmt.Sprintf("the server rejected our request for an unknown reason (get secrets %s)", impersonationProxyTLSSecretName)
|
expectedErr := fmt.Sprintf("the server rejected our request for an unknown reason (get secrets %s)", impersonationProxyTLSSecretName(env))
|
||||||
require.EqualError(t, err, expectedErr)
|
require.EqualError(t, err, expectedErr)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update configuration to force the proxy to disabled mode
|
// Update configuration to force the proxy to disabled mode
|
||||||
configMap := configMapForConfig(t, impersonator.Config{Mode: impersonator.ModeDisabled})
|
configMap := configMapForConfig(t, env, impersonator.Config{Mode: impersonator.ModeDisabled})
|
||||||
if env.HasCapability(library.HasExternalLoadBalancerProvider) {
|
if env.HasCapability(library.HasExternalLoadBalancerProvider) {
|
||||||
t.Logf("creating configmap %s", configMap.Name)
|
t.Logf("creating configmap %s", configMap.Name)
|
||||||
_, err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Create(ctx, &configMap, metav1.CreateOptions{})
|
_, err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Create(ctx, &configMap, metav1.CreateOptions{})
|
||||||
@ -396,7 +389,7 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
// The load balancer should not exist after we disable the impersonation proxy.
|
// The load balancer should not exist after we disable the impersonation proxy.
|
||||||
// Note that this can take kind of a long time on real cloud providers (e.g. ~22 seconds on EKS).
|
// Note that this can take kind of a long time on real cloud providers (e.g. ~22 seconds on EKS).
|
||||||
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
||||||
hasService, err := hasImpersonationProxyLoadBalancerService(ctx, adminClient, env.ConciergeNamespace)
|
hasService, err := hasImpersonationProxyLoadBalancerService(ctx, env, adminClient)
|
||||||
return !hasService, err
|
return !hasService, err
|
||||||
}, time.Minute, 500*time.Millisecond)
|
}, time.Minute, 500*time.Millisecond)
|
||||||
}
|
}
|
||||||
@ -417,17 +410,17 @@ func TestImpersonationProxy(t *testing.T) {
|
|||||||
|
|
||||||
// Check that the generated TLS cert Secret was deleted by the controller.
|
// Check that the generated TLS cert Secret was deleted by the controller.
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
_, err = adminClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName, metav1.GetOptions{})
|
_, err = adminClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, impersonationProxyTLSSecretName(env), metav1.GetOptions{})
|
||||||
return k8serrors.IsNotFound(err)
|
return k8serrors.IsNotFound(err)
|
||||||
}, 10*time.Second, 250*time.Millisecond)
|
}, 10*time.Second, 250*time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configMapForConfig(t *testing.T, config impersonator.Config) corev1.ConfigMap {
|
func configMapForConfig(t *testing.T, env *library.TestEnv, config impersonator.Config) corev1.ConfigMap {
|
||||||
configString, err := yaml.Marshal(config)
|
configString, err := yaml.Marshal(config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
configMap := corev1.ConfigMap{
|
configMap := corev1.ConfigMap{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: impersonationProxyConfigMapName,
|
Name: impersonationProxyConfigMapName(env),
|
||||||
},
|
},
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
"config.yaml": string(configString),
|
"config.yaml": string(configString),
|
||||||
@ -435,8 +428,8 @@ func configMapForConfig(t *testing.T, config impersonator.Config) corev1.ConfigM
|
|||||||
return configMap
|
return configMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasImpersonationProxyLoadBalancerService(ctx context.Context, client kubernetes.Interface, namespace string) (bool, error) {
|
func hasImpersonationProxyLoadBalancerService(ctx context.Context, env *library.TestEnv, client kubernetes.Interface) (bool, error) {
|
||||||
service, err := client.CoreV1().Services(namespace).Get(ctx, impersonationProxyLoadBalancerName, metav1.GetOptions{})
|
service, err := client.CoreV1().Services(env.ConciergeNamespace).Get(ctx, impersonationProxyLoadBalancerName(env), metav1.GetOptions{})
|
||||||
if k8serrors.IsNotFound(err) {
|
if k8serrors.IsNotFound(err) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@ -446,8 +439,8 @@ func hasImpersonationProxyLoadBalancerService(ctx context.Context, client kubern
|
|||||||
return service.Spec.Type == corev1.ServiceTypeLoadBalancer, nil
|
return service.Spec.Type == corev1.ServiceTypeLoadBalancer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImpersonationProxyLoadBalancerIngress(ctx context.Context, client kubernetes.Interface, namespace string) (*corev1.LoadBalancerIngress, error) {
|
func getImpersonationProxyLoadBalancerIngress(ctx context.Context, env *library.TestEnv, client kubernetes.Interface) (*corev1.LoadBalancerIngress, error) {
|
||||||
service, err := client.CoreV1().Services(namespace).Get(ctx, impersonationProxyLoadBalancerName, metav1.GetOptions{})
|
service, err := client.CoreV1().Services(env.ConciergeNamespace).Get(ctx, impersonationProxyLoadBalancerName(env), metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -460,3 +453,19 @@ func getImpersonationProxyLoadBalancerIngress(ctx context.Context, client kubern
|
|||||||
}
|
}
|
||||||
return &ingresses[0], nil
|
return &ingresses[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func impersonationProxyConfigMapName(env *library.TestEnv) string {
|
||||||
|
return env.ConciergeAppName + "-impersonation-proxy-config"
|
||||||
|
}
|
||||||
|
|
||||||
|
func impersonationProxyTLSSecretName(env *library.TestEnv) string {
|
||||||
|
return env.ConciergeAppName + "-impersonation-proxy-tls-serving-certificate"
|
||||||
|
}
|
||||||
|
|
||||||
|
func impersonationProxyCASecretName(env *library.TestEnv) string {
|
||||||
|
return env.ConciergeAppName + "-impersonation-proxy-ca-certificate"
|
||||||
|
}
|
||||||
|
|
||||||
|
func impersonationProxyLoadBalancerName(env *library.TestEnv) string {
|
||||||
|
return env.ConciergeAppName + "-impersonation-proxy-load-balancer"
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user