diff --git a/chart/crds/druid.apache.org_druidingestions.yaml b/chart/crds/druid.apache.org_druidingestions.yaml
index 70e7fe47..b5f09c5f 100644
--- a/chart/crds/druid.apache.org_druidingestions.yaml
+++ b/chart/crds/druid.apache.org_druidingestions.yaml
@@ -47,6 +47,10 @@ spec:
properties:
auth:
properties:
+ passwordKey:
+ description: PasswordKey specifies the key within the Kubernetes
+ secret that contains the password for authentication.
+ type: string
secretRef:
description: |-
SecretReference represents a Secret Reference. It has enough information to retrieve secret
@@ -64,6 +68,10 @@ spec:
x-kubernetes-map-type: atomic
type:
type: string
+ usernameKey:
+ description: UsernameKey specifies the key within the Kubernetes
+ secret that contains the username for authentication.
+ type: string
required:
- secretRef
- type
diff --git a/chart/crds/druid.apache.org_druids.yaml b/chart/crds/druid.apache.org_druids.yaml
index 9bec0105..20d7d37b 100644
--- a/chart/crds/druid.apache.org_druids.yaml
+++ b/chart/crds/druid.apache.org_druids.yaml
@@ -1267,6 +1267,10 @@ spec:
type: object
auth:
properties:
+ passwordKey:
+ description: PasswordKey specifies the key within the Kubernetes
+ secret that contains the password for authentication.
+ type: string
secretRef:
description: |-
SecretReference represents a Secret Reference. It has enough information to retrieve secret
@@ -1284,6 +1288,10 @@ spec:
x-kubernetes-map-type: atomic
type:
type: string
+ usernameKey:
+ description: UsernameKey specifies the key within the Kubernetes
+ secret that contains the username for authentication.
+ type: string
required:
- secretRef
- type
diff --git a/config/crd/bases/druid.apache.org_druidingestions.yaml b/config/crd/bases/druid.apache.org_druidingestions.yaml
index 70e7fe47..b5f09c5f 100644
--- a/config/crd/bases/druid.apache.org_druidingestions.yaml
+++ b/config/crd/bases/druid.apache.org_druidingestions.yaml
@@ -47,6 +47,10 @@ spec:
properties:
auth:
properties:
+ passwordKey:
+ description: PasswordKey specifies the key within the Kubernetes
+ secret that contains the password for authentication.
+ type: string
secretRef:
description: |-
SecretReference represents a Secret Reference. It has enough information to retrieve secret
@@ -64,6 +68,10 @@ spec:
x-kubernetes-map-type: atomic
type:
type: string
+ usernameKey:
+ description: UsernameKey specifies the key within the Kubernetes
+ secret that contains the username for authentication.
+ type: string
required:
- secretRef
- type
diff --git a/config/crd/bases/druid.apache.org_druids.yaml b/config/crd/bases/druid.apache.org_druids.yaml
index 9bec0105..20d7d37b 100644
--- a/config/crd/bases/druid.apache.org_druids.yaml
+++ b/config/crd/bases/druid.apache.org_druids.yaml
@@ -1267,6 +1267,10 @@ spec:
type: object
auth:
properties:
+ passwordKey:
+ description: PasswordKey specifies the key within the Kubernetes
+ secret that contains the password for authentication.
+ type: string
secretRef:
description: |-
SecretReference represents a Secret Reference. It has enough information to retrieve secret
@@ -1284,6 +1288,10 @@ spec:
x-kubernetes-map-type: atomic
type:
type: string
+ usernameKey:
+ description: UsernameKey specifies the key within the Kubernetes
+ secret that contains the username for authentication.
+ type: string
required:
- secretRef
- type
diff --git a/docs/api_specifications/druid.md b/docs/api_specifications/druid.md
index 993205d5..4517835b 100644
--- a/docs/api_specifications/druid.md
+++ b/docs/api_specifications/druid.md
@@ -173,56 +173,6 @@ Kubernetes core/v1.ResourceRequirements
-
Auth
-
-
-(Appears on:
-DruidIngestionSpec)
-
-
-AuthType
-(string alias)
-
-(Appears on:
-Auth)
-
DeepStorageSpec
@@ -909,6 +859,29 @@ string
+dynamicConfig
+
+k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
+(Optional)
+ Dynamic Configurations for Druid. Applied through the dynamic configuration API.
+ |
+
+
+
+auth
+
+github.com/datainfrahq/druid-operator/pkg/druidapi.Auth
+
+ |
+
+(Optional)
+ |
+
+
+
dnsPolicy
@@ -1156,9 +1129,7 @@ IngestionSpec
auth
-
-Auth
-
+github.com/datainfrahq/druid-operator/pkg/druidapi.Auth
|
@@ -1243,9 +1214,7 @@ IngestionSpec
|
auth
-
-Auth
-
+github.com/datainfrahq/druid-operator/pkg/druidapi.Auth
|
@@ -1344,6 +1313,18 @@ string
|
+ CurrentIngestionSpec is a string instead of RawExtension to maintain compatibility with existing
+IngestionSpecs that are stored as JSON strings.
+ |
+ |
+
+
+rules
+
+[]k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
|
@@ -1972,6 +1953,30 @@ Kubernetes autoscaling/v2.HorizontalPodAutoscalerSpec
+serviceAccountName
+
+string
+
+ |
+
+(Optional)
+ ServiceAccountName Kubernetes native serviceAccountName specification.
+ |
+
+
+
+dynamicConfig
+
+k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
+(Optional)
+ Dynamic Configurations for Druid. Applied through the dynamic configuration API.
+ |
+
+
+
dnsPolicy
@@ -2684,6 +2689,29 @@ string
|
+dynamicConfig
+
+k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
+(Optional)
+ Dynamic Configurations for Druid. Applied through the dynamic configuration API.
+ |
+
+
+
+auth
+
+github.com/datainfrahq/druid-operator/pkg/druidapi.Auth
+
+ |
+
+(Optional)
+ |
+
+
+
dnsPolicy
@@ -2750,12 +2778,52 @@ string
|
+(Optional)
+ Spec should be passed in as a JSON string.
+Note: This field is planned for deprecation in favor of nativeSpec.
|
+
+
+nativeSpec
+
+k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
+(Optional)
+ nativeSpec allows the ingestion specification to be defined in a native Kubernetes format.
+This is particularly useful for environment-specific configurations and will eventually
+replace the JSON-based Spec field.
+Note: Spec will be ignored if nativeSpec is provided.
+ |
+
+
+
+compaction
+
+k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
+(Optional)
+ |
+
+
+
+rules
+
+[]k8s.io/apimachinery/pkg/runtime.RawExtension
+
+ |
+
+(Optional)
+ |
+
diff --git a/go.mod b/go.mod
index 14ca62f7..01f34480 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
+ github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-logr/zapr v1.2.4 // indirect
diff --git a/go.sum b/go.sum
index 76aaa3b6..43ed29b7 100644
--- a/go.sum
+++ b/go.sum
@@ -23,6 +23,7 @@ github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
diff --git a/pkg/druidapi/druidapi.go b/pkg/druidapi/druidapi.go
index 8b020dcb..effda506 100644
--- a/pkg/druidapi/druidapi.go
+++ b/pkg/druidapi/druidapi.go
@@ -30,6 +30,12 @@ type Auth struct {
Type AuthType `json:"type"`
// +required
SecretRef v1.SecretReference `json:"secretRef"`
+
+ // UsernameKey specifies the key within the Kubernetes secret that contains the username for authentication.
+ UsernameKey string `json:"usernameKey,omitempty"`
+
+ // PasswordKey specifies the key within the Kubernetes secret that contains the password for authentication.
+ PasswordKey string `json:"passwordKey,omitempty"`
}
// GetAuthCreds retrieves basic authentication credentials from a Kubernetes secret.
@@ -42,12 +48,23 @@ type Auth struct {
//
// Returns:
//
-// BasicAuth: The basic authentication credentials.
+// BasicAuth: The basic authentication credentials, or an error if authentication retrieval fails.
func GetAuthCreds(
ctx context.Context,
c client.Client,
auth Auth,
) (internalhttp.BasicAuth, error) {
+ userNameKey := OperatorUserName
+ passwordKey := OperatorPassword
+
+ if auth.UsernameKey != "" {
+ userNameKey = auth.UsernameKey
+ }
+
+ if auth.PasswordKey != "" {
+ passwordKey = auth.PasswordKey
+ }
+
// Check if the mentioned secret exists
if auth != (Auth{}) {
secret := v1.Secret{}
@@ -57,9 +74,18 @@ func GetAuthCreds(
}, &secret); err != nil {
return internalhttp.BasicAuth{}, err
}
+
+ if _, ok := secret.Data[userNameKey]; !ok {
+ return internalhttp.BasicAuth{}, fmt.Errorf("username key %q not found in secret %s/%s", userNameKey, auth.SecretRef.Namespace, auth.SecretRef.Name)
+ }
+
+ if _, ok := secret.Data[passwordKey]; !ok {
+ return internalhttp.BasicAuth{}, fmt.Errorf("password key %q not found in secret %s/%s", passwordKey, auth.SecretRef.Namespace, auth.SecretRef.Name)
+ }
+
creds := internalhttp.BasicAuth{
- UserName: string(secret.Data[OperatorUserName]),
- Password: string(secret.Data[OperatorPassword]),
+ UserName: string(secret.Data[userNameKey]),
+ Password: string(secret.Data[passwordKey]),
}
return creds, nil
diff --git a/pkg/druidapi/druidapi_test.go b/pkg/druidapi/druidapi_test.go
index 3b94e993..10a686c1 100644
--- a/pkg/druidapi/druidapi_test.go
+++ b/pkg/druidapi/druidapi_test.go
@@ -1,9 +1,119 @@
package druidapi
import (
+ "context"
+ internalhttp "github.com/datainfrahq/druid-operator/pkg/http"
+ "github.com/stretchr/testify/assert"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
)
+func TestGetAuthCreds(t *testing.T) {
+ tests := []struct {
+ name string
+ auth Auth
+ expected internalhttp.BasicAuth
+ expectErr bool
+ }{
+ {
+ name: "default keys present",
+ auth: Auth{
+ Type: BasicAuth,
+ SecretRef: v1.SecretReference{Name: "test-default", Namespace: "test"},
+ },
+ expected: internalhttp.BasicAuth{UserName: "test-user", Password: "test-password"},
+ expectErr: false,
+ },
+ {
+ name: "custom keys present",
+ auth: Auth{
+ Type: BasicAuth,
+ SecretRef: v1.SecretReference{Name: "test", Namespace: "default"},
+ UsernameKey: "usr",
+ PasswordKey: "pwd",
+ },
+ expected: internalhttp.BasicAuth{UserName: "admin", Password: "admin"},
+ expectErr: false,
+ },
+ {
+ name: "custom user key is missing",
+ auth: Auth{
+ Type: BasicAuth,
+ SecretRef: v1.SecretReference{Name: "test", Namespace: "default"},
+ UsernameKey: "nope",
+ PasswordKey: "pwd",
+ },
+ expected: internalhttp.BasicAuth{},
+ expectErr: true,
+ },
+ {
+ name: "custom user key with default password key",
+ auth: Auth{
+ Type: BasicAuth,
+ SecretRef: v1.SecretReference{Name: "test", Namespace: "default"},
+ UsernameKey: "usr",
+ },
+ expected: internalhttp.BasicAuth{UserName: "admin", Password: "also-admin"},
+ expectErr: false,
+ },
+ {
+ name: "custom password key is missing",
+ auth: Auth{
+ Type: BasicAuth,
+ SecretRef: v1.SecretReference{Name: "test", Namespace: "default"},
+ UsernameKey: "usr",
+ PasswordKey: "nope",
+ },
+ expected: internalhttp.BasicAuth{},
+ expectErr: true,
+ },
+ {
+ name: "empty auth struct returns no creds",
+ auth: Auth{},
+ expected: internalhttp.BasicAuth{},
+ expectErr: false,
+ },
+ }
+
+ client := fake.NewClientBuilder().
+ WithObjects(&v1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-default",
+ Namespace: "test",
+ },
+ Data: map[string][]byte{
+ OperatorUserName: []byte("test-user"),
+ OperatorPassword: []byte("test-password"),
+ },
+ }).
+ WithObjects(&v1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test",
+ Namespace: "default",
+ },
+ Data: map[string][]byte{
+ "usr": []byte("admin"),
+ "pwd": []byte("admin"),
+ OperatorPassword: []byte("also-admin"),
+ },
+ }).Build()
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ actual, err := GetAuthCreds(context.TODO(), client, tt.auth)
+ if tt.expectErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ }
+
+ assert.Equal(t, tt.expected, actual)
+ })
+ }
+}
+
func TestMakePath(t *testing.T) {
tests := []struct {
name string