diff --git a/examples/kong-consumer-key-auth.yaml b/examples/kong-consumer-key-auth.yaml new file mode 100644 index 0000000000..7b6b583287 --- /dev/null +++ b/examples/kong-consumer-key-auth.yaml @@ -0,0 +1,82 @@ +apiVersion: configuration.konghq.com/v1 +kind: KongConsumer +metadata: + name: consumer1 + annotations: + kubernetes.io/ingress.class: kong +username: consumer1 +credentials: +- consumer1-auth +--- +apiVersion: v1 +kind: Secret +metadata: + name: consumer1-auth + labels: + konghq.com/credential: key-auth +type: Opaque +stringData: + key: password +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin-deployment + labels: + app: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + template: + metadata: + labels: + app: httpbin + spec: + containers: + - name: httpbin + image: kong/httpbin:0.1.0 + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: httpbin + name: httpbin-deployment +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: httpbin + type: ClusterIP +--- +apiVersion: configuration.konghq.com/v1 +kind: KongPlugin +metadata: + name: key-auth-1 +plugin: key-auth +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: httpbin-ingress + annotations: + konghq.com/strip-path: "true" + konghq.com/plugins: key-auth-1 +spec: + ingressClassName: kong + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: httpbin-deployment + port: + number: 80 diff --git a/internal/admission/validation/consumers/credentials/validation.go b/internal/admission/validation/consumers/credentials/validation.go index 7bea486875..5ba0825b6a 100644 --- a/internal/admission/validation/consumers/credentials/validation.go +++ b/internal/admission/validation/consumers/credentials/validation.go @@ -112,12 +112,13 @@ type Index map[string]map[string]map[string]struct{} // and will validate it for both normal structure validation and for // unique key constraint violations. func (cs Index) ValidateCredentialsForUniqueKeyConstraints(secret *corev1.Secret) error { - // the indication of credential type is required to be present on all credentials. - credentialTypeB, ok := secret.Data[TypeKey] - if !ok { - return fmt.Errorf("missing required key %s", TypeKey) + credentialType, credentialSource := util.ExtractKongCredentialType(secret) + if credentialSource == util.CredentialTypeAbsent { + return fmt.Errorf( + "secret has no credential type, add a %s label", + labels.LabelPrefix+labels.CredentialKey, + ) } - credentialType := string(credentialTypeB) // the additional key/values are optional, but must be validated // for unique constraint violations. Using an index of credentials diff --git a/internal/admission/validator_test.go b/internal/admission/validator_test.go index 832a7c4de5..eb9e124b9a 100644 --- a/internal/admission/validator_test.go +++ b/internal/admission/validator_test.go @@ -16,6 +16,9 @@ import ( corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + testk8sclient "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/kong/kubernetes-ingress-controller/v3/internal/annotations" "github.com/kong/kubernetes-ingress-controller/v3/internal/store" @@ -562,6 +565,7 @@ func fakeClassMatcher(*metav1.ObjectMeta, string, annotations.ClassMatching) boo func TestKongHTTPValidator_ValidateCredential(t *testing.T) { testCases := []struct { name string + consumers []kongv1.KongConsumer secret corev1.Secret wantOK bool wantMessage string @@ -606,6 +610,29 @@ func TestKongHTTPValidator_ValidateCredential(t *testing.T) { }, wantOK: true, }, + { + name: "valid key-auth credential using only konghq.com/credential with a consumer gets accepted", + consumers: []kongv1.KongConsumer{ + { + Username: "username", + Credentials: []string{ + "username-key-auth-1", + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "username-key-auth-1", + Labels: map[string]string{ + "konghq.com/credential": "key-auth", + }, + }, + Data: map[string][]byte{ + "key": []byte("my-key"), + }, + }, + wantOK: true, + }, { name: "invalid key-auth credential with no consumers gets rejected", secret: corev1.Secret{ @@ -622,8 +649,16 @@ func TestKongHTTPValidator_ValidateCredential(t *testing.T) { for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { + scheme := runtime.NewScheme() + require.NoError(t, testk8sclient.AddToScheme(scheme)) + require.NoError(t, kongv1.AddToScheme(scheme)) + b := fake.NewClientBuilder().WithScheme(scheme) + validator := KongHTTPValidator{ - ConsumerGetter: fakeConsumerGetter{}, + ManagerClient: b.Build(), + ConsumerGetter: fakeConsumerGetter{ + consumers: tc.consumers, + }, AdminAPIServicesProvider: fakeServicesProvider{}, ingressClassMatcher: fakeClassMatcher, Logger: logr.Discard(),