diff --git a/src/go/k8s/Makefile b/src/go/k8s/Makefile index 5418c2c08d92..9652f200cf2e 100644 --- a/src/go/k8s/Makefile +++ b/src/go/k8s/Makefile @@ -31,17 +31,17 @@ all: manager # Run tests ENVTEST_ASSETS_DIR=$(shell pwd)/testbin -test: generate fmt vet manifests +test: generate vet manifests mkdir -p ${ENVTEST_ASSETS_DIR} test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.7.0/hack/setup-envtest.sh source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test --race -v ./... -coverprofile cover.out # Build manager binary -manager: generate fmt vet +manager: generate vet go build -o bin/manager main.go # Run against the configured Kubernetes cluster in ~/.kube/config -run: generate fmt vet manifests +run: generate vet manifests go run ./main.go # Install CRDs into a cluster @@ -69,10 +69,6 @@ undeploy: manifests: controller-gen $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases -# Run crlfmt against code -fmt: crlfmt - $(CRLFMT) -w -wrap=80 -ignore '_generated.deepcopy.go$$' . - # Run go vet against code vet: go vet ./... @@ -123,36 +119,41 @@ helm-e2e-tests: kuttl test docker-build docker-build-configurator echo "~~~ Running kuttl tests :k8s:" $(KUTTL) test --config kuttl-helm-test.yaml $(TEST_ONLY_FLAG) $(KUTTL_TEST_FLAGS) -# Download controller-gen locally if necessary -CONTROLLER_GEN = $(shell pwd)/bin/controller-gen -controller-gen: - $(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1) - -# Download kuttl locally if necessary -KUTTL = $(shell pwd)/bin/kubectl-kuttl -kuttl: - $(call go-get-tool,$(KUTTL),github.com/kudobuilder/kuttl/cmd/kubectl-kuttl@v0.11.1) - -# Download crlfmt locally if necessary -CRLFMT = $(shell pwd)/bin/crlfmt -crlfmt: - $(call go-get-tool,$(CRLFMT),github.com/cockroachdb/crlfmt@v0.0.0-20210128092314-b3eff0b87c79) - -# Download kustomize locally if necessary -KUSTOMIZE = $(shell pwd)/bin/kustomize -kustomize: - $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7) - -# go-get-tool will 'go get' any package $2 and install it to $1. -PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) -define go-get-tool -@[ -f $(1) ] || { \ -set -e ;\ -TMP_DIR=$$(mktemp -d) ;\ -cd $$TMP_DIR ;\ -go mod init tmp ;\ -echo "Downloading $(2)" ;\ -GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\ -rm -rf $$TMP_DIR ;\ -} -endef +##@ Build Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +## Tool Binaries +KUSTOMIZE ?= $(LOCALBIN)/kustomize +CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen +ENVTEST ?= $(LOCALBIN)/setup-envtest +KUTTL ?= $(LOCALBIN)/kubectl-kuttl + +## Tool Versions +KUSTOMIZE_VERSION ?= v3.8.7 +CONTROLLER_TOOLS_VERSION ?= v0.4.1 +KUTTL_VERSION ?= v0.13.0 + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. +$(CONTROLLER_GEN): $(LOCALBIN) + test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + +KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. +$(KUSTOMIZE): $(LOCALBIN) + test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); } + +.PHONY: envtest +envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +$(ENVTEST): $(LOCALBIN) + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + +.PHONY: kuttl +kuttl: $(KUTTL) +$(KUTTL): $(LOCALBIN) + test -s $(LOCALBIN)/kubectl-kuttl || GOBIN=$(LOCALBIN) go install github.com/kudobuilder/kuttl/cmd/kubectl-kuttl@$(KUTTL_VERSION) diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go index 916dda11c586..3efb19694183 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go @@ -129,7 +129,19 @@ type ClusterSpec struct { // List of superusers Superusers []Superuser `json:"superUsers,omitempty"` // SASL enablement flag + // +optional + // Deprecated: replaced by "kafkaEnableAuthorization" EnableSASL bool `json:"enableSasl,omitempty"` + // Enable authorization for Kafka connections. Values are: + // + // - `nil`: Ignored. Authorization is enabled with `enable_sasl: true` + // + // - `true`: authorization is required + // + // - `false`: authorization is disabled; + // + // See also `enableSasl` and `configuration.kafkaApi[].authenticationMethod` + KafkaEnableAuthorization *bool `json:"kafkaEnableAuthorization,omitempty"` // For configuration parameters not exposed, a map can be provided for string values. // Such values are passed transparently to Redpanda. The key format is ".field", e.g., // @@ -541,6 +553,10 @@ type KafkaAPI struct { External ExternalConnectivityConfig `json:"external,omitempty"` // Configuration of TLS for Kafka API TLS KafkaAPITLS `json:"tls,omitempty"` + // AuthenticationMethod can enable authentication method per Kafka + // listener. Available options are: none, sasl, mtls_identity. + // https://docs.redpanda.com/docs/security/authentication/ + AuthenticationMethod string `json:"authenticationMethod,omitempty"` } // PandaproxyAPI configures listener for the Pandaproxy API @@ -552,6 +568,9 @@ type PandaproxyAPI struct { External PandaproxyExternalConnectivityConfig `json:"external,omitempty"` // Configuration of TLS for Pandaproxy API TLS PandaproxyAPITLS `json:"tls,omitempty"` + // AuthenticationMethod can enable authentication method per pandaproxy + // listener. Available options are: none, http_basic. + AuthenticationMethod string `json:"authenticationMethod,omitempty"` } // SchemaRegistryAPI configures the schema registry API @@ -566,6 +585,9 @@ type SchemaRegistryAPI struct { External *SchemaRegistryExternalConnectivityConfig `json:"external,omitempty"` // TLS is the configuration for schema registry TLS *SchemaRegistryAPITLS `json:"tls,omitempty"` + // AuthenticationMethod can enable authentication method per schema registry + // listener. Available options are: none, http_basic. + AuthenticationMethod string `json:"authenticationMethod,omitempty"` } // SchemaRegistryExternalConnectivityConfig defines the external connectivity @@ -889,9 +911,10 @@ func (r *Cluster) AdminAPIURLs() []string { // PandaproxyAPIInternal returns internal pandaproxy listener func (r *Cluster) PandaproxyAPIInternal() *PandaproxyAPI { - for _, el := range r.Spec.Configuration.PandaproxyAPI { - if !el.External.Enabled { - return &el + proxies := r.Spec.Configuration.PandaproxyAPI + for i := range proxies { + if !proxies[i].External.Enabled { + return &proxies[i] } } return nil @@ -899,9 +922,10 @@ func (r *Cluster) PandaproxyAPIInternal() *PandaproxyAPI { // PandaproxyAPIExternal returns the external pandaproxy listener func (r *Cluster) PandaproxyAPIExternal() *PandaproxyAPI { - for _, el := range r.Spec.Configuration.PandaproxyAPI { - if el.External.Enabled { - return &el + proxies := r.Spec.Configuration.PandaproxyAPI + for i := range proxies { + if proxies[i].External.Enabled { + return &proxies[i] } } return nil @@ -910,9 +934,10 @@ func (r *Cluster) PandaproxyAPIExternal() *PandaproxyAPI { // PandaproxyAPITLS returns a Pandaproxy listener that has TLS enabled. // It returns nil if no TLS is configured. func (r *Cluster) PandaproxyAPITLS() *PandaproxyAPI { - for i, el := range r.Spec.Configuration.PandaproxyAPI { - if el.TLS.Enabled { - return &r.Spec.Configuration.PandaproxyAPI[i] + proxies := r.Spec.Configuration.PandaproxyAPI + for i := range proxies { + if proxies[i].TLS.Enabled { + return &proxies[i] } } return nil @@ -1168,3 +1193,12 @@ func defaultTLSConfig() *TLSConfig { NodeSecretRef: nil, } } + +// IsSASLOnInternalEnabled replaces single check if sasl is enabled with multiple +// check. The external kafka listener is excluded from the check as panda proxy, +// schema registry and console should use internal kafka listener even if we have +// external enabled. +func (r *Cluster) IsSASLOnInternalEnabled() bool { + return r.Spec.KafkaEnableAuthorization != nil && *r.Spec.KafkaEnableAuthorization || + r.Spec.EnableSASL +} diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go index 93baa685f631..f959c5280243 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go @@ -44,6 +44,10 @@ const ( transactionCoordinatorReplicationKey = "redpanda.transaction_coordinator_replication" idAllocatorReplicationKey = "redpanda.id_allocator_replication" + noneAuthorizationMechanism = "none" + saslAuthorizationMechanism = "sasl" + mTLSIdentityAuthorizationMechanism = "mtls_identity" + defaultSchemaRegistryPort = 8081 ) @@ -126,6 +130,12 @@ func (r *Cluster) Default() { if r.Spec.LicenseRef != nil && r.Spec.LicenseRef.Key == "" { r.Spec.LicenseRef.Key = DefaultLicenseSecretKey } + + for i := range r.Spec.Configuration.KafkaAPI { + if r.Spec.Configuration.KafkaAPI[i].AuthenticationMethod == "" { + r.Spec.Configuration.KafkaAPI[i].AuthenticationMethod = noneAuthorizationMechanism + } + } } var defaultAdditionalConfiguration = map[string]int{ @@ -359,6 +369,18 @@ func (r *Cluster) validateKafkaListeners() field.ErrorList { &p.External, field.NewPath("spec").Child("configuration").Child("kafkaApi").Index(i).Child("external")) allErrs = append(allErrs, tlsErrs...) + + switch r.Spec.Configuration.KafkaAPI[i].AuthenticationMethod { + case noneAuthorizationMechanism: + case saslAuthorizationMechanism: + case mTLSIdentityAuthorizationMechanism: + break + default: + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("kafkaApi").Index(i).Child("authenticationMethod"), + r.Spec.Configuration.KafkaAPI[i].AuthenticationMethod, + "authentication method is invalid. Valid options are: none, sasl, mtls_identity")) + } } allErrs = append(allErrs, @@ -422,8 +444,9 @@ func (r *Cluster) validatePandaproxyListeners() field.ErrorList { var allErrs field.ErrorList var proxyExternal *PandaproxyAPI kafkaExternal := r.ExternalListener() - for i, p := range r.Spec.Configuration.PandaproxyAPI { - if !p.External.Enabled { + p := r.Spec.Configuration.PandaproxyAPI + for i := range r.Spec.Configuration.PandaproxyAPI { + if !p[i].External.Enabled { continue } if proxyExternal != nil { @@ -499,8 +522,8 @@ func (r *Cluster) validatePandaproxyListeners() field.ErrorList { // for now only one listener can have TLS to be backward compatible with v1alpha1 API foundListenerWithTLS := false - for i, p := range r.Spec.Configuration.PandaproxyAPI { - if p.TLS.Enabled { + for i := range r.Spec.Configuration.PandaproxyAPI { + if p[i].TLS.Enabled { if foundListenerWithTLS { allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("configuration").Child("pandaproxyApi").Index(i).Child("tls"), @@ -510,12 +533,12 @@ func (r *Cluster) validatePandaproxyListeners() field.ErrorList { foundListenerWithTLS = true } tlsErrs := validateListener( - p.TLS.Enabled, - p.TLS.RequireClientAuth, - p.TLS.IssuerRef, - p.TLS.NodeSecretRef, + p[i].TLS.Enabled, + p[i].TLS.RequireClientAuth, + p[i].TLS.IssuerRef, + p[i].TLS.NodeSecretRef, field.NewPath("spec").Child("configuration").Child("pandaproxyApi").Index(i).Child("tls"), - &p.External.ExternalConnectivityConfig, + &p[i].External.ExternalConnectivityConfig, field.NewPath("spec").Child("configuration").Child("pandaproxyApi").Index(i).Child("external"), ) allErrs = append(allErrs, tlsErrs...) diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go index 2fd3ded5846c..c04915d2a456 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go @@ -313,7 +313,7 @@ func TestValidateUpdate_NoError(t *testing.T) { Spec: v1alpha1.ClusterSpec{ Replicas: pointer.Int32Ptr(replicas2), Configuration: v1alpha1.RedpandaConfig{ - KafkaAPI: []v1alpha1.KafkaAPI{{Port: 124}}, + KafkaAPI: []v1alpha1.KafkaAPI{{Port: 124, AuthenticationMethod: "none"}}, AdminAPI: []v1alpha1.AdminAPI{{Port: 125}}, RPCServer: v1alpha1.SocketAddress{Port: 126}, SchemaRegistry: &v1alpha1.SchemaRegistryAPI{Port: 127}, @@ -380,7 +380,7 @@ func TestValidateUpdate_NoError(t *testing.T) { updatePort := redpandaCluster.DeepCopy() updatePort.Spec.Configuration.KafkaAPI[0].Port = 200 updatePort.Spec.Configuration.KafkaAPI = append(updatePort.Spec.Configuration.KafkaAPI, - v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{Enabled: true}}) + v1alpha1.KafkaAPI{AuthenticationMethod: "none", External: v1alpha1.ExternalConnectivityConfig{Enabled: true}}) updatePort.Spec.Configuration.PandaproxyAPI = append(updatePort.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.PandaproxyExternalConnectivityConfig{ExternalConnectivityConfig: v1alpha1.ExternalConnectivityConfig{Enabled: true}}}) updatePort.Spec.Configuration.SchemaRegistry.External = &v1alpha1.SchemaRegistryExternalConnectivityConfig{ @@ -581,8 +581,9 @@ func TestValidateUpdate_NoError(t *testing.T) { t.Run("pandaproxy tls can specify issuerref", func(t *testing.T) { tls := redpandaCluster.DeepCopy() tls.Spec.Configuration.KafkaAPI = append(tls.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{ - External: v1alpha1.ExternalConnectivityConfig{Enabled: true, Subdomain: "cluster.com"}, - Port: 30092, + AuthenticationMethod: "none", + External: v1alpha1.ExternalConnectivityConfig{Enabled: true, Subdomain: "cluster.com"}, + Port: 30092, }) tls.Spec.Configuration.PandaproxyAPI = append(tls.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{ External: v1alpha1.PandaproxyExternalConnectivityConfig{ @@ -735,7 +736,7 @@ func TestCreation(t *testing.T) { newPort := redpandaCluster.DeepCopy() newPort.Spec.Configuration.KafkaAPI[0].Port = 200 newPort.Spec.Configuration.KafkaAPI = append(newPort.Spec.Configuration.KafkaAPI, - v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{Enabled: true}}) + v1alpha1.KafkaAPI{AuthenticationMethod: "none", External: v1alpha1.ExternalConnectivityConfig{Enabled: true}}) newPort.Spec.Configuration.PandaproxyAPI = append(newPort.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.PandaproxyExternalConnectivityConfig{ExternalConnectivityConfig: v1alpha1.ExternalConnectivityConfig{Enabled: true}}}) newPort.Spec.Configuration.SchemaRegistry.External = &v1alpha1.SchemaRegistryExternalConnectivityConfig{ @@ -1096,15 +1097,17 @@ func TestCreation(t *testing.T) { err := rp.ValidateCreate() assert.Error(t, err) }) - //nolint:dupl // not really a duplicate t.Run("endpoint allowed for schemaregistry", func(t *testing.T) { rp := redpandaCluster.DeepCopy() const commonDomain = "company.org" - rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ - Enabled: true, - Subdomain: commonDomain, - }}) + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{ + AuthenticationMethod: "none", + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }, + }) rp.Spec.Configuration.SchemaRegistry = &v1alpha1.SchemaRegistryAPI{External: &v1alpha1.SchemaRegistryExternalConnectivityConfig{ ExternalConnectivityConfig: v1alpha1.ExternalConnectivityConfig{ Enabled: true, @@ -1187,15 +1190,17 @@ func TestCreation(t *testing.T) { t.Run("valid endpoint template in kafka API", func(t *testing.T) { rp := redpandaCluster.DeepCopy() - rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ - Enabled: true, - Subdomain: "example.com", - EndpointTemplate: "{{.Index}}-broker", - }}) + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{ + AuthenticationMethod: "none", + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "example.com", + EndpointTemplate: "{{.Index}}-broker", + }, + }) err := rp.ValidateCreate() assert.NoError(t, err) }) - //nolint:dupl // not really a duplicate t.Run("invalid endpoint template in pandaproxy API", func(t *testing.T) { rp := redpandaCluster.DeepCopy() @@ -1212,15 +1217,17 @@ func TestCreation(t *testing.T) { err := rp.ValidateCreate() assert.Error(t, err) }) - //nolint:dupl // not really a duplicate t.Run("valid endpoint template in pandaproxy API", func(t *testing.T) { rp := redpandaCluster.DeepCopy() const commonDomain = "mydomain" - rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ - Enabled: true, - Subdomain: commonDomain, - }}) + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{ + AuthenticationMethod: "none", + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }, + }) rp.Spec.Configuration.PandaproxyAPI = append(rp.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.PandaproxyExternalConnectivityConfig{ExternalConnectivityConfig: v1alpha1.ExternalConnectivityConfig{ Enabled: true, Subdomain: commonDomain, @@ -1233,10 +1240,13 @@ func TestCreation(t *testing.T) { rp := redpandaCluster.DeepCopy() const commonDomain = "mydomain" - rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ - Enabled: true, - Subdomain: commonDomain, - }}) + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{ + AuthenticationMethod: "none", + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }, + }) rp.Spec.Configuration.PandaproxyAPI = append(rp.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.PandaproxyExternalConnectivityConfig{ ExternalConnectivityConfig: v1alpha1.ExternalConnectivityConfig{ Enabled: true, @@ -1291,7 +1301,6 @@ func TestSchemaRegistryValidations(t *testing.T) { err := schemaReg.ValidateCreate() assert.Error(t, err) }) - //nolint:dupl // the tests are not duplicates t.Run("schema registry externally available is valid when it has the same subdomain as kafka external listener", func(t *testing.T) { schemaReg := redpandaCluster.DeepCopy() schemaReg.Spec.Configuration.SchemaRegistry = &v1alpha1.SchemaRegistryAPI{ @@ -1300,7 +1309,7 @@ func TestSchemaRegistryValidations(t *testing.T) { }, } schemaReg.Spec.Configuration.KafkaAPI = append(schemaReg.Spec.Configuration.KafkaAPI, - v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{Enabled: true, Subdomain: "test.com"}}) + v1alpha1.KafkaAPI{AuthenticationMethod: "none", External: v1alpha1.ExternalConnectivityConfig{Enabled: true, Subdomain: "test.com"}}) err := schemaReg.ValidateCreate() assert.NoError(t, err) @@ -1370,7 +1379,7 @@ func validRedpandaCluster() *v1alpha1.Cluster { Spec: v1alpha1.ClusterSpec{ Replicas: pointer.Int32Ptr(1), Configuration: v1alpha1.RedpandaConfig{ - KafkaAPI: []v1alpha1.KafkaAPI{{Port: 124}}, + KafkaAPI: []v1alpha1.KafkaAPI{{Port: 124, AuthenticationMethod: "none"}}, AdminAPI: []v1alpha1.AdminAPI{{Port: 126}}, RPCServer: v1alpha1.SocketAddress{Port: 128}, SchemaRegistry: &v1alpha1.SchemaRegistryAPI{Port: 130}, @@ -1569,10 +1578,10 @@ func TestRangesAndCollisions(t *testing.T) { c.Spec.Configuration.SchemaRegistry = nil if tc.kafkaInternal != 0 { - c.Spec.Configuration.KafkaAPI = append(c.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{Port: tc.kafkaInternal}) + c.Spec.Configuration.KafkaAPI = append(c.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{AuthenticationMethod: "none", Port: tc.kafkaInternal}) } if tc.kafkaExternal != 0 { - c.Spec.Configuration.KafkaAPI = append(c.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{Port: tc.kafkaExternal, External: v1alpha1.ExternalConnectivityConfig{Enabled: true}}) + c.Spec.Configuration.KafkaAPI = append(c.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{AuthenticationMethod: "none", Port: tc.kafkaExternal, External: v1alpha1.ExternalConnectivityConfig{Enabled: true}}) } if tc.adminAPIInternal != 0 { c.Spec.Configuration.AdminAPI = append(c.Spec.Configuration.AdminAPI, v1alpha1.AdminAPI{Port: tc.adminAPIInternal}) @@ -1607,6 +1616,7 @@ func TestRangesAndCollisions(t *testing.T) { } } +//nolint:funlen // this is ok for a test func TestKafkaTLSRules(t *testing.T) { rpCluster := validRedpandaCluster() @@ -1633,7 +1643,6 @@ func TestKafkaTLSRules(t *testing.T) { assert.Error(t, err) }) - //nolint:dupl // the tests are not duplicates t.Run("same issuer for two tls listeners is allowed", func(t *testing.T) { newRp := rpCluster.DeepCopy() newRp.Spec.Configuration.KafkaAPI[0].TLS = v1alpha1.KafkaAPITLS{ @@ -1644,13 +1653,19 @@ func TestKafkaTLSRules(t *testing.T) { }, } newRp.Spec.Configuration.KafkaAPI = append(newRp.Spec.Configuration.KafkaAPI, - v1alpha1.KafkaAPI{Port: 30001, External: v1alpha1.ExternalConnectivityConfig{Enabled: true, Subdomain: "redpanda.com"}, TLS: v1alpha1.KafkaAPITLS{ - Enabled: true, - IssuerRef: &cmmeta.ObjectReference{ - Name: "issuer", - Kind: "ClusterIssuer", + v1alpha1.KafkaAPI{ + AuthenticationMethod: "none", + Port: 30001, + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, Subdomain: "redpanda.com", + }, TLS: v1alpha1.KafkaAPITLS{ + Enabled: true, + IssuerRef: &cmmeta.ObjectReference{ + Name: "issuer", + Kind: "ClusterIssuer", + }, }, - }}) + }) err := newRp.ValidateUpdate(rpCluster) assert.NoError(t, err) @@ -1679,7 +1694,6 @@ func TestKafkaTLSRules(t *testing.T) { assert.Error(t, err) }) - //nolint:dupl // the tests are not duplicates t.Run("same nodesecretref for two tls listeners is allowed", func(t *testing.T) { newRp := rpCluster.DeepCopy() newRp.Spec.Configuration.KafkaAPI[0].TLS = v1alpha1.KafkaAPITLS{ @@ -1690,19 +1704,88 @@ func TestKafkaTLSRules(t *testing.T) { }, } newRp.Spec.Configuration.KafkaAPI = append(newRp.Spec.Configuration.KafkaAPI, - v1alpha1.KafkaAPI{Port: 30001, External: v1alpha1.ExternalConnectivityConfig{Enabled: true, Subdomain: "redpanda.com"}, TLS: v1alpha1.KafkaAPITLS{ - Enabled: true, - NodeSecretRef: &corev1.ObjectReference{ - Name: "node", - Namespace: "default", + v1alpha1.KafkaAPI{ + AuthenticationMethod: "none", + Port: 30001, + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "redpanda.com", }, - }}) + TLS: v1alpha1.KafkaAPITLS{ + Enabled: true, + NodeSecretRef: &corev1.ObjectReference{ + Name: "node", + Namespace: "default", + }, + }, + }) err := newRp.ValidateUpdate(rpCluster) assert.NoError(t, err) }) } +func TestKafkaAuthenticationMethod(t *testing.T) { + rpCluster := validRedpandaCluster() + + t.Run("no authentication method provided", func(t *testing.T) { + newRp := rpCluster.DeepCopy() + newRp.Spec.Configuration.KafkaAPI = append(newRp.Spec.Configuration.KafkaAPI, + v1alpha1.KafkaAPI{ + AuthenticationMethod: "", + Port: 30001, + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "redpanda.com", + }, + }) + + err := newRp.ValidateCreate() + assert.Error(t, err) + + err = newRp.ValidateUpdate(rpCluster) + assert.Error(t, err) + }) + + t.Run("sasl authentication method provided", func(t *testing.T) { + newRp := rpCluster.DeepCopy() + newRp.Spec.Configuration.KafkaAPI = append(newRp.Spec.Configuration.KafkaAPI, + v1alpha1.KafkaAPI{ + AuthenticationMethod: "sasl", + Port: 30001, + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "redpanda.com", + }, + }) + + err := newRp.ValidateCreate() + assert.NoError(t, err) + + err = newRp.ValidateUpdate(rpCluster) + assert.NoError(t, err) + }) + + t.Run("mtls_identity authentication method provided", func(t *testing.T) { + newRp := rpCluster.DeepCopy() + newRp.Spec.Configuration.KafkaAPI = append(newRp.Spec.Configuration.KafkaAPI, + v1alpha1.KafkaAPI{ + AuthenticationMethod: "mtls_identity", + Port: 30001, + External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "redpanda.com", + }, + }) + + err := newRp.ValidateCreate() + assert.NoError(t, err) + + err = newRp.ValidateUpdate(rpCluster) + assert.NoError(t, err) + }) +} + func TestCloudStorage(t *testing.T) { rpCluster := validRedpandaCluster() diff --git a/src/go/k8s/apis/redpanda/v1alpha1/zz_generated.deepcopy.go b/src/go/k8s/apis/redpanda/v1alpha1/zz_generated.deepcopy.go index e992ee902c8a..d1cef495668f 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/zz_generated.deepcopy.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/zz_generated.deepcopy.go @@ -230,6 +230,11 @@ func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { *out = make([]Superuser, len(*in)) copy(*out, *in) } + if in.KafkaEnableAuthorization != nil { + in, out := &in.KafkaEnableAuthorization, &out.KafkaEnableAuthorization + *out = new(bool) + **out = **in + } if in.AdditionalConfiguration != nil { in, out := &in.AdditionalConfiguration, &out.AdditionalConfiguration *out = make(map[string]string, len(*in)) diff --git a/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml b/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml index c74da0091134..6adc965c18c4 100644 --- a/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml +++ b/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml @@ -248,6 +248,11 @@ spec: items: description: KafkaAPI configures listener for the Kafka API properties: + authenticationMethod: + description: 'AuthenticationMethod can enable authentication + method per Kafka listener. Available options are: none, + sasl, mtls_identity. https://docs.redpanda.com/docs/security/authentication/' + type: string external: description: External enables user to expose Redpanda nodes outside of a Kubernetes cluster. For more information @@ -396,6 +401,11 @@ spec: description: PandaproxyAPI configures listener for the Pandaproxy API properties: + authenticationMethod: + description: 'AuthenticationMethod can enable authentication + method per pandaproxy listener. Available options are: + none, http_basic.' + type: string external: description: External enables user to expose Redpanda nodes outside of a Kubernetes cluster. For more information @@ -567,6 +577,11 @@ spec: description: SchemaRegistryAPI configures the schema registry API properties: + authenticationMethod: + description: 'AuthenticationMethod can enable authentication + method per schema registry listener. Available options are: + none, http_basic.' + type: string external: description: External enables user to expose Redpanda nodes outside of a Kubernetes cluster. For more information please @@ -724,11 +739,17 @@ spec: fully-qualified DNS name. http://www.dns-sd.org/trailingdotsindomainnames.html type: boolean enableSasl: - description: SASL enablement flag + description: 'SASL enablement flag Deprecated: replaced by "kafkaEnableAuthorization"' type: boolean image: description: Image is the fully qualified name of the Redpanda container type: string + kafkaEnableAuthorization: + description: "Enable authorization for Kafka connections. Values are: + \n - `nil`: Ignored. Authorization is enabled with `enable_sasl: + true` \n - `true`: authorization is required \n - `false`: authorization + is disabled; \n See also `enableSasl` and `configuration.kafkaApi[].authenticationMethod`" + type: boolean licenseRef: description: If key is not provided in the SecretRef, Secret data should have key "license" diff --git a/src/go/k8s/config/e2e-tests/kustomization.yaml b/src/go/k8s/config/e2e-tests/kustomization.yaml new file mode 100644 index 000000000000..5cccdb87e34d --- /dev/null +++ b/src/go/k8s/config/e2e-tests/kustomization.yaml @@ -0,0 +1,13 @@ +bases: +- ../default + +patchesStrategicMerge: +- manager.yaml + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: vectorized/redpanda-operator + newName: localhost/redpanda-operator + newTag: dev + diff --git a/src/go/k8s/config/e2e-tests/manager.yaml b/src/go/k8s/config/e2e-tests/manager.yaml new file mode 100644 index 000000000000..a089ebc653ac --- /dev/null +++ b/src/go/k8s/config/e2e-tests/manager.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + imagePullPolicy: IfNotPresent + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" + - "--webhook-enabled=true" + - "--configurator-base-image=localhost/configurator" + - "--configurator-tag=dev" + - "--configurator-image-pull-policy=IfNotPresent" diff --git a/src/go/k8s/config/rbac/role.yaml b/src/go/k8s/config/rbac/role.yaml index a3694b3a9e9c..2335f8b27fc1 100644 --- a/src/go/k8s/config/rbac/role.yaml +++ b/src/go/k8s/config/rbac/role.yaml @@ -73,6 +73,7 @@ rules: - configmaps verbs: - create + - delete - get - list - patch @@ -103,6 +104,7 @@ rules: - create - get - list + - update - watch - apiGroups: - "" diff --git a/src/go/k8s/controllers/redpanda/cluster_controller.go b/src/go/k8s/controllers/redpanda/cluster_controller.go index 70a80558e8e9..9d42f606a7b8 100644 --- a/src/go/k8s/controllers/redpanda/cluster_controller.go +++ b/src/go/k8s/controllers/redpanda/cluster_controller.go @@ -65,9 +65,9 @@ type ClusterReconciler struct { //+kubebuilder:rbac:groups=redpanda.vectorized.io,resources=clusters/finalizers,verbs=update //+kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch; -//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch; +//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;delete -//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create; +//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update; //+kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;create;update;patch; //+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings,verbs=get;list;watch;create;update;patch; //+kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch @@ -149,13 +149,13 @@ func (r *ClusterReconciler) Reconcile( var proxySu *resources.SuperUsersResource var proxySuKey types.NamespacedName - if redpandaCluster.Spec.EnableSASL && redpandaCluster.PandaproxyAPIInternal() != nil { + if redpandaCluster.IsSASLOnInternalEnabled() && redpandaCluster.PandaproxyAPIInternal() != nil { proxySu = resources.NewSuperUsers(r.Client, &redpandaCluster, r.Scheme, resources.ScramPandaproxyUsername, resources.PandaProxySuffix, log) proxySuKey = proxySu.Key() } var schemaRegistrySu *resources.SuperUsersResource var schemaRegistrySuKey types.NamespacedName - if redpandaCluster.Spec.EnableSASL && redpandaCluster.Spec.Configuration.SchemaRegistry != nil { + if redpandaCluster.IsSASLOnInternalEnabled() && redpandaCluster.Spec.Configuration.SchemaRegistry != nil { schemaRegistrySu = resources.NewSuperUsers(r.Client, &redpandaCluster, r.Scheme, resources.ScramSchemaRegistryUsername, resources.SchemaRegistrySuffix, log) schemaRegistrySuKey = schemaRegistrySu.Key() } diff --git a/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go b/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go index 06ab429beb5b..a9903e98f989 100644 --- a/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go +++ b/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go @@ -108,13 +108,13 @@ func (r *ClusterConfigurationDriftReconciler) Reconcile( var proxySu *resources.SuperUsersResource var proxySuKey types.NamespacedName - if redpandaCluster.Spec.EnableSASL && redpandaCluster.PandaproxyAPIInternal() != nil { + if redpandaCluster.IsSASLOnInternalEnabled() && redpandaCluster.PandaproxyAPIInternal() != nil { proxySu = resources.NewSuperUsers(r.Client, &redpandaCluster, r.Scheme, resources.ScramPandaproxyUsername, resources.PandaProxySuffix, log) proxySuKey = proxySu.Key() } var schemaRegistrySu *resources.SuperUsersResource var schemaRegistrySuKey types.NamespacedName - if redpandaCluster.Spec.EnableSASL && redpandaCluster.Spec.Configuration.SchemaRegistry != nil { + if redpandaCluster.IsSASLOnInternalEnabled() && redpandaCluster.Spec.Configuration.SchemaRegistry != nil { schemaRegistrySu = resources.NewSuperUsers(r.Client, &redpandaCluster, r.Scheme, resources.ScramSchemaRegistryUsername, resources.SchemaRegistrySuffix, log) schemaRegistrySuKey = schemaRegistrySu.Key() } diff --git a/src/go/k8s/controllers/redpanda/console_controller.go b/src/go/k8s/controllers/redpanda/console_controller.go index c2269161eeec..9f0962893e7f 100644 --- a/src/go/k8s/controllers/redpanda/console_controller.go +++ b/src/go/k8s/controllers/redpanda/console_controller.go @@ -110,13 +110,14 @@ func (r *ConsoleReconciler) Reconcile( return ctrl.Result{}, err } + r.Log.V(debugLogLevel).Info("console", "observed generation", console.Status.ObservedGeneration, "generation", console.GetGeneration()) var s state switch { case console.GetDeletionTimestamp() != nil: s = &Deleting{r} case !console.GenerationMatchesObserved(): if err := r.handleSpecChange(ctx, console); err != nil { - return ctrl.Result{}, fmt.Errorf("handle spec change: %w", err) + return ctrl.Result{}, fmt.Errorf("handle spec change (lastObserved: %d, currentGeneration: %d): %w", console.Status.ObservedGeneration, console.GetGeneration(), err) } fallthrough default: @@ -199,6 +200,7 @@ func (r *Reconciling) Do( } if !console.GenerationMatchesObserved() { + r.Log.Info("observed generation updating", "observed generation", console.Status.ObservedGeneration, "generation", console.GetGeneration()) console.Status.ObservedGeneration = console.GetGeneration() if err := r.Status().Update(ctx, console); err != nil { return ctrl.Result{}, err @@ -237,11 +239,13 @@ func (r *ConsoleReconciler) handleSpecChange( ctx context.Context, console *redpandav1alpha1.Console, ) error { if console.Status.ConfigMapRef != nil { + r.Log.V(debugLogLevel).Info("handle spec change", "config map name", console.Status.ConfigMapRef.Name, "config map namespace", console.Status.ConfigMapRef.Namespace) // We are creating new ConfigMap for every spec change so Deployment can detect changes and redeploy Pods // Unset Status.ConfigMapRef so we can delete the previous unused ConfigMap + previousConfigMapRef := fmt.Sprintf("%s/%s", console.Status.ConfigMapRef.Namespace, console.Status.ConfigMapRef.Name) console.Status.ConfigMapRef = nil if err := r.Status().Update(ctx, console); err != nil { - return err + return fmt.Errorf("removing config map ref from status (%s): %w", previousConfigMapRef, err) } } return nil diff --git a/src/go/k8s/controllers/redpanda/console_controller_test.go b/src/go/k8s/controllers/redpanda/console_controller_test.go index 63dcbdb2f183..153bd2dfabff 100644 --- a/src/go/k8s/controllers/redpanda/console_controller_test.go +++ b/src/go/k8s/controllers/redpanda/console_controller_test.go @@ -91,12 +91,9 @@ var _ = Describe("Console controller", func() { By("Having a Secret for SASL user") secretLookupKey := types.NamespacedName{Name: fmt.Sprintf("%s-%s", ConsoleName, resources.ConsoleSuffix), Namespace: ConsoleNamespace} createdSecret := &corev1.Secret{} - Eventually(func() bool { - if err := k8sClient.Get(ctx, secretLookupKey, createdSecret); err != nil { - return false - } - return true - }, timeout, interval).Should(BeTrue()) + Eventually(func() error { + return k8sClient.Get(ctx, secretLookupKey, createdSecret) + }, timeout, interval).Should(Succeed()) // Not checking if ACLs are created, KafkaAdmin is mocked @@ -192,23 +189,50 @@ var _ = Describe("Console controller", func() { console.SetLabels(map[string]string{"test.redpanda.vectorized.io/name": "updating-console"}) }), timeout, interval).Should(Succeed()) - By("Checking ConfigMapRef did not change") + By("Checking updated console label exist") Eventually(func() bool { updatedConsole := &redpandav1alpha1.Console{} if err := k8sClient.Get(ctx, consoleLookupKey, updatedConsole); err != nil { return false } labels := updatedConsole.GetLabels() - if newLabel, ok := labels["test.redpanda.vectorized.io/name"]; !ok || newLabel != "updating-console" { + _, ok := labels["test.redpanda.vectorized.io/name"] + return ok + }, timeout, interval).Should(BeTrue()) + + By("Checking updated console label content") + Eventually(func() string { + updatedConsole := &redpandav1alpha1.Console{} + if err := k8sClient.Get(ctx, consoleLookupKey, updatedConsole); err != nil { + return "" + } + labels := updatedConsole.GetLabels() + return labels["test.redpanda.vectorized.io/name"] + }, timeout, interval).Should(Equal("updating-console")) + + By("Checking ConfigMapRef exist in status") + Eventually(func() bool { + updatedConsole := &redpandav1alpha1.Console{} + if err := k8sClient.Get(ctx, consoleLookupKey, updatedConsole); err != nil { return false } + + updatedRef := updatedConsole.Status.ConfigMapRef + return updatedRef != nil + }, timeout, interval).Should(BeTrue()) + + By("Checking ConfigMapRef did not change") + Eventually(func() string { + updatedConsole := &redpandav1alpha1.Console{} + if err := k8sClient.Get(ctx, consoleLookupKey, updatedConsole); err != nil { + return "console not found" + } updatedRef := updatedConsole.Status.ConfigMapRef if updatedRef == nil { - return false + return "missing config map reference" } - updatedConfigmapNsn := fmt.Sprintf("%s/%s", updatedRef.Namespace, updatedRef.Name) - return updatedConfigmapNsn == configmapNsn - }, timeout, interval).Should(BeTrue()) + return fmt.Sprintf("%s/%s", updatedRef.Namespace, updatedRef.Name) + }, timeout, interval).Should(Equal(configmapNsn)) }) }) diff --git a/src/go/k8s/hack/install-cert-manager.sh b/src/go/k8s/hack/install-cert-manager.sh index 66afcdb10dcf..e268bb3952fd 100755 --- a/src/go/k8s/hack/install-cert-manager.sh +++ b/src/go/k8s/hack/install-cert-manager.sh @@ -21,4 +21,4 @@ else fi kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.4.4/cert-manager.yaml -./bin/cm-verifier +./bin/cm-verifier --timeout 5m diff --git a/src/go/k8s/kuttl-test.yaml b/src/go/k8s/kuttl-test.yaml index 20327f1644b8..e0919107d0cd 100644 --- a/src/go/k8s/kuttl-test.yaml +++ b/src/go/k8s/kuttl-test.yaml @@ -4,6 +4,7 @@ startKIND: true kindContainers: - localhost/redpanda-operator:dev - localhost/configurator:dev + - localhost/redpanda:dev testDirs: - ./tests/e2e kindConfig: ./kind.yaml @@ -12,9 +13,7 @@ commands: - command: "kubectl taint nodes -l node-role.kubernetes.io/master= node-role.kubernetes.io/master:NoSchedule-" - command: "./hack/install-cert-manager.sh" - command: "kubectl create -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/e23ff77fceba6a5d9f190f5d1a123c87701dc964/bundle.yaml" - - command: "sh -c 'cd config/manager && kustomize edit set image vectorized/redpanda-operator=localhost/redpanda-operator:dev'" - - command: "sh -c 'kustomize build config/default | kubectl apply -f -'" - - command: "kind load docker-image localhost/redpanda:dev" + - command: "sh -c 'kustomize build config/e2e-tests | kubectl apply -f -'" - command: "./hack/wait-for-webhook-ready.sh" - command: "mkdir -p tests/_e2e_artifacts" artifactsDir: tests/_e2e_artifacts diff --git a/src/go/k8s/pkg/console/admin.go b/src/go/k8s/pkg/console/admin.go index 2155d61cf7b0..e15a0b24ab74 100644 --- a/src/go/k8s/pkg/console/admin.go +++ b/src/go/k8s/pkg/console/admin.go @@ -59,7 +59,7 @@ func NewKafkaAdmin( ctx context.Context, cl client.Client, cluster *redpandav1alpha1.Cluster, store *Store, ) (KafkaAdminClient, error) { opts := []kgo.Opt{kgo.SeedBrokers(getBrokers(cluster)...)} - if cluster.Spec.EnableSASL { + if cluster.IsSASLOnInternalEnabled() { sasl, err := getSASLOpt(ctx, cl, cluster) if err != nil { return nil, err diff --git a/src/go/k8s/pkg/console/configmap.go b/src/go/k8s/pkg/console/configmap.go index 6695b365427f..837c6ba1b25d 100644 --- a/src/go/k8s/pkg/console/configmap.go +++ b/src/go/k8s/pkg/console/configmap.go @@ -52,6 +52,7 @@ func NewConfigMap( // Ensure implements Resource interface func (cm *ConfigMap) Ensure(ctx context.Context) error { if cm.consoleobj.Status.ConfigMapRef != nil { + cm.log.V(debugLogLevel).Info("config map ref still exist", "config map name", cm.consoleobj.Status.ConfigMapRef.Name, "config map namespace", cm.consoleobj.Status.ConfigMapRef.Namespace) return nil } @@ -108,6 +109,7 @@ func (cm *ConfigMap) Ensure(ctx context.Context) error { // Other Resources may set Console status if they are also watching GenerationMatchesObserved() cm.consoleobj.Status.ConfigMapRef = &corev1.ObjectReference{Namespace: obj.GetNamespace(), Name: obj.GetName()} + cm.log.Info("config map ref updated", "config map name", cm.consoleobj.Status.ConfigMapRef.Name, "config map namespace", cm.consoleobj.Status.ConfigMapRef.Namespace) return nil } @@ -457,7 +459,7 @@ func (cm *ConfigMap) genKafka(username, password string) kafka.Config { sasl := kafka.SASLConfig{Enabled: false} // Set defaults because Console complains SASL mechanism is not set even if SASL is disabled sasl.SetDefaults() - if yes := cm.clusterobj.Spec.EnableSASL; yes { + if yes := cm.clusterobj.IsSASLOnInternalEnabled(); yes { sasl = kafka.SASLConfig{ Enabled: yes, Username: username, @@ -552,6 +554,7 @@ func (cm *ConfigMap) buildConfigCluster( // ConfigMaps are recreated upon Console update, old ones should be cleaned up func (cm *ConfigMap) DeleteUnused(ctx context.Context) error { if ref := cm.consoleobj.Status.ConfigMapRef; ref != nil { + cm.log.Info("delete unused config map reference", "config map name", ref.Name, "config map namespace", ref.Namespace) if err := cm.delete(ctx, ref.Name); err != nil { return err } diff --git a/src/go/k8s/pkg/resources/certmanager/type_helpers.go b/src/go/k8s/pkg/resources/certmanager/type_helpers.go index f0a676af5371..88b94ad28ea6 100644 --- a/src/go/k8s/pkg/resources/certmanager/type_helpers.go +++ b/src/go/k8s/pkg/resources/certmanager/type_helpers.go @@ -87,8 +87,9 @@ func schemaRegistryAPIListeners(r *redpandav1alpha1.Cluster) []APIListener { // PandaProxyAPIListeners returns all PandaProxyAPI listeners func pandaProxyAPIListeners(r *redpandav1alpha1.Cluster) []APIListener { listeners := []APIListener{} - for _, el := range r.Spec.Configuration.PandaproxyAPI { - listeners = append(listeners, el) + pp := r.Spec.Configuration.PandaproxyAPI + for i := range r.Spec.Configuration.PandaproxyAPI { + listeners = append(listeners, pp[i]) } return listeners } diff --git a/src/go/k8s/pkg/resources/configmap.go b/src/go/k8s/pkg/resources/configmap.go index b635b9fc78da..8889628b18c4 100644 --- a/src/go/k8s/pkg/resources/configmap.go +++ b/src/go/k8s/pkg/resources/configmap.go @@ -224,18 +224,29 @@ func (r *ConfigMapResource) CreateConfiguration( cr := &cfg.NodeConfiguration.Redpanda internalListener := r.pandaCluster.InternalListener() + internalAuthN := &internalListener.AuthenticationMethod + if *internalAuthN == "" { + internalAuthN = nil + } cr.KafkaAPI = []config.NamedAuthNSocketAddress{} // we don't want to inherit default kafka port cr.KafkaAPI = append(cr.KafkaAPI, config.NamedAuthNSocketAddress{ Address: "0.0.0.0", Port: internalListener.Port, Name: InternalListenerName, + AuthN: internalAuthN, }) - if r.pandaCluster.ExternalListener() != nil { + externalListener := r.pandaCluster.ExternalListener() + if externalListener != nil { + externalAuthN := &externalListener.AuthenticationMethod + if *externalAuthN == "" { + externalAuthN = nil + } cr.KafkaAPI = append(cr.KafkaAPI, config.NamedAuthNSocketAddress{ Address: "0.0.0.0", Port: calculateExternalPort(internalListener.Port, r.pandaCluster.ExternalListener().Port), Name: ExternalListenerName, + AuthN: externalAuthN, }) } @@ -258,15 +269,16 @@ func (r *ConfigMapResource) CreateConfiguration( cr.DeveloperMode = c.DeveloperMode cr.Directory = dataDirectory - for _, tl := range r.pandaCluster.KafkaTLSListeners() { + kl := r.pandaCluster.KafkaTLSListeners() + for i := range kl { tls := config.ServerTLS{ - Name: tl.Name, + Name: kl[i].Name, KeyFile: fmt.Sprintf("%s/%s", mountPoints.KafkaAPI.NodeCertMountDir, corev1.TLSPrivateKeyKey), // tls.key CertFile: fmt.Sprintf("%s/%s", mountPoints.KafkaAPI.NodeCertMountDir, corev1.TLSCertKey), // tls.crt Enabled: true, - RequireClientAuth: tl.TLS.RequireClientAuth, + RequireClientAuth: kl[i].TLS.RequireClientAuth, } - if tl.TLS.RequireClientAuth { + if kl[i].TLS.RequireClientAuth { tls.TruststoreFile = fmt.Sprintf("%s/%s", mountPoints.KafkaAPI.ClientCAMountDir, cmetav1.TLSCAKey) } cr.KafkaAPITLS = append(cr.KafkaAPITLS, tls) @@ -307,6 +319,9 @@ func (r *ConfigMapResource) CreateConfiguration( if r.pandaCluster.Spec.EnableSASL { cfg.SetAdditionalRedpandaProperty("enable_sasl", true) } + if r.pandaCluster.Spec.KafkaEnableAuthorization != nil && *r.pandaCluster.Spec.KafkaEnableAuthorization { + cfg.SetAdditionalRedpandaProperty("kafka_enable_authorization", true) + } partitions := r.pandaCluster.Spec.Configuration.GroupTopicPartitions if partitions != 0 { @@ -341,11 +356,16 @@ func (r *ConfigMapResource) CreateConfiguration( } if sr := r.pandaCluster.Spec.Configuration.SchemaRegistry; sr != nil { - cfg.NodeConfiguration.SchemaRegistry.SchemaRegistryAPI = []config.NamedSocketAddress{ + var authN *string + if sr.AuthenticationMethod != "" { + authN = &sr.AuthenticationMethod + } + cfg.NodeConfiguration.SchemaRegistry.SchemaRegistryAPI = []config.NamedAuthNSocketAddress{ { Address: "0.0.0.0", Port: sr.Port, Name: SchemaRegistryPortName, + AuthN: authN, }, } } @@ -444,20 +464,31 @@ func (r *ConfigMapResource) preparePandaproxy(cfgRpk *config.Config) { return } - cfgRpk.Pandaproxy.PandaproxyAPI = []config.NamedSocketAddress{ + var internalAuthN *string + if internal.AuthenticationMethod != "" { + internalAuthN = &internal.AuthenticationMethod + } + cfgRpk.Pandaproxy.PandaproxyAPI = []config.NamedAuthNSocketAddress{ { Address: "0.0.0.0", Port: internal.Port, Name: PandaproxyPortInternalName, + AuthN: internalAuthN, }, } - if r.pandaCluster.PandaproxyAPIExternal() != nil { + var externalAuthN *string + external := r.pandaCluster.PandaproxyAPIExternal() + if external != nil { + if external.AuthenticationMethod != "" { + externalAuthN = &external.AuthenticationMethod + } cfgRpk.Pandaproxy.PandaproxyAPI = append(cfgRpk.Pandaproxy.PandaproxyAPI, - config.NamedSocketAddress{ + config.NamedAuthNSocketAddress{ Address: "0.0.0.0", Port: calculateExternalPort(internal.Port, r.pandaCluster.PandaproxyAPIExternal().Port), Name: PandaproxyPortExternalName, + AuthN: externalAuthN, }) } } @@ -478,7 +509,7 @@ func (r *ConfigMapResource) preparePandaproxyClient( }) } - if !r.pandaCluster.Spec.EnableSASL { + if !r.pandaCluster.IsSASLOnInternalEnabled() { return nil } @@ -517,7 +548,7 @@ func (r *ConfigMapResource) prepareSchemaRegistryClient( }) } - if !r.pandaCluster.Spec.EnableSASL { + if !r.pandaCluster.IsSASLOnInternalEnabled() { return nil } diff --git a/src/go/k8s/pkg/resources/configmap_test.go b/src/go/k8s/pkg/resources/configmap_test.go index 2d48fc27f760..b4c6203d6b51 100644 --- a/src/go/k8s/pkg/resources/configmap_test.go +++ b/src/go/k8s/pkg/resources/configmap_test.go @@ -30,7 +30,7 @@ import ( func TestEnsureConfigMap(t *testing.T) { require.NoError(t, redpandav1alpha1.AddToScheme(scheme.Scheme)) clusterWithExternal := pandaCluster().DeepCopy() - clusterWithExternal.Spec.Configuration.KafkaAPI = append(clusterWithExternal.Spec.Configuration.KafkaAPI, redpandav1alpha1.KafkaAPI{Port: 30001, External: redpandav1alpha1.ExternalConnectivityConfig{Enabled: true}}) + clusterWithExternal.Spec.Configuration.KafkaAPI = append(clusterWithExternal.Spec.Configuration.KafkaAPI, redpandav1alpha1.KafkaAPI{AuthenticationMethod: "sasl", Port: 30001, External: redpandav1alpha1.ExternalConnectivityConfig{Enabled: true}}) clusterWithMultipleKafkaTLS := pandaCluster().DeepCopy() clusterWithMultipleKafkaTLS.Spec.Configuration.KafkaAPI[0].TLS = redpandav1alpha1.KafkaAPITLS{Enabled: true} clusterWithMultipleKafkaTLS.Spec.Configuration.KafkaAPI = append(clusterWithMultipleKafkaTLS.Spec.Configuration.KafkaAPI, redpandav1alpha1.KafkaAPI{Port: 30001, TLS: redpandav1alpha1.KafkaAPITLS{Enabled: true}, External: redpandav1alpha1.ExternalConnectivityConfig{Enabled: true}}) @@ -105,7 +105,7 @@ func TestEnsureConfigMap_AdditionalConfig(t *testing.T) { name: "Primitive object in additional configuration", additionalConfiguration: map[string]string{"redpanda.transactional_id_expiration_ms": "25920000000", "rpk.overprovisioned": "true"}, expectedStrings: []string{"transactional_id_expiration_ms: 25920000000"}, - expectedHash: "5a3cf863cd61e3cfda0c586fad11c13c", + expectedHash: "1bb3d2cecc19b8e2ecc5872b1c5964da", }, { name: "Complex struct in additional configuration", @@ -115,7 +115,7 @@ func TestEnsureConfigMap_AdditionalConfig(t *testing.T) { - address: 0.0.0.0 port: 8081 name: external`}, - expectedHash: "24f0b08129b48a3c8f091f13b84e1f1d", + expectedHash: "8452040fd894a74dbbdedff300162dc0", }, { name: "shadow index cache directory", @@ -123,7 +123,7 @@ func TestEnsureConfigMap_AdditionalConfig(t *testing.T) { `cloud_storage_cache_directory: /var/lib/shadow-index-cache`, `cloud_storage_cache_size: "10737418240"`, }, - expectedHash: "e3ab006a8c5db2957c16f982bc6db694", + expectedHash: "a971c1871fd690525231074448daf077", }, } for _, tc := range testcases { diff --git a/src/go/k8s/pkg/resources/featuregates/featuregates.go b/src/go/k8s/pkg/resources/featuregates/featuregates.go index 791ddf0a80d3..84948a67ec65 100644 --- a/src/go/k8s/pkg/resources/featuregates/featuregates.go +++ b/src/go/k8s/pkg/resources/featuregates/featuregates.go @@ -18,8 +18,9 @@ import ( ) var ( - v22_1 = mustSemVer("v22.1.0") - v21_11 = mustSemVer("v21.11.0") + v22_1 = mustSemVer("v22.1.0") + v21_11 = mustSemVer("v21.11.0") + v22_2_1 = mustSemVer("v22.2.1") ) // ShadowIndex feature gate should be removed in 3 version starting @@ -41,6 +42,12 @@ func MaintenanceMode(version string) bool { return atLeastVersion(v22_1, version) } +// PerListenerAuthorization feature gate should be removed when the operator +// will no longer support 22.2.1 or older versions +func PerListenerAuthorization(version string) bool { + return atLeastVersion(v22_2_1, version) +} + // atLeastVersion tells if the given version is greater or equal than the // minVersion. // All semver incompatible versions (such as "dev" or "latest") and non-version diff --git a/src/go/k8s/pkg/resources/featuregates/featuregates_test.go b/src/go/k8s/pkg/resources/featuregates/featuregates_test.go index 32bc866df2d7..438178736a48 100644 --- a/src/go/k8s/pkg/resources/featuregates/featuregates_test.go +++ b/src/go/k8s/pkg/resources/featuregates/featuregates_test.go @@ -16,54 +16,62 @@ import ( "github.com/stretchr/testify/assert" ) -func TestFeatureGates(t *testing.T) { +func TestFeatureGates(t *testing.T) { //nolint:funlen // table tests can be longer cases := []struct { version string shadowIndex bool centralizedConfiguration bool maintenanceMode bool + perListenerAuthorization bool }{ { version: "v21.1.1", shadowIndex: false, centralizedConfiguration: false, maintenanceMode: false, + perListenerAuthorization: false, }, { version: "v21.11.1", shadowIndex: true, centralizedConfiguration: false, maintenanceMode: false, + perListenerAuthorization: false, }, { version: "v21.12.1", shadowIndex: true, centralizedConfiguration: false, maintenanceMode: false, + perListenerAuthorization: false, }, { version: "v22.1.1", shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: false, }, { version: "v22.1.2", shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: false, }, { version: "v22.2.1", shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: true, }, { version: "dev", shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: true, }, // Versions from: https://hub.docker.com/r/vectorized/redpanda/tags { @@ -71,24 +79,28 @@ func TestFeatureGates(t *testing.T) { shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: true, }, { version: "v21.11.20-beta2", shadowIndex: true, centralizedConfiguration: false, maintenanceMode: false, + perListenerAuthorization: false, }, { version: "v21.11.20-beta2-amd64", shadowIndex: true, centralizedConfiguration: false, maintenanceMode: false, + perListenerAuthorization: false, }, { version: "v22.2.3-arm64", shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: true, }, // Versions from: https://hub.docker.com/r/vectorized/redpanda-nightly/tags { @@ -96,6 +108,7 @@ func TestFeatureGates(t *testing.T) { shadowIndex: true, centralizedConfiguration: true, maintenanceMode: true, + perListenerAuthorization: true, }, } @@ -104,9 +117,11 @@ func TestFeatureGates(t *testing.T) { si := featuregates.ShadowIndex(tc.version) cc := featuregates.CentralizedConfiguration(tc.version) mm := featuregates.MaintenanceMode(tc.version) + pl := featuregates.PerListenerAuthorization(tc.version) assert.Equal(t, tc.shadowIndex, si) assert.Equal(t, tc.centralizedConfiguration, cc) assert.Equal(t, tc.maintenanceMode, mm) + assert.Equal(t, tc.perListenerAuthorization, pl) }) } } diff --git a/src/go/k8s/pkg/resources/statefulset_test.go b/src/go/k8s/pkg/resources/statefulset_test.go index 6397141da59e..b18fe1b02d9e 100644 --- a/src/go/k8s/pkg/resources/statefulset_test.go +++ b/src/go/k8s/pkg/resources/statefulset_test.go @@ -265,7 +265,7 @@ func pandaCluster() *redpandav1alpha1.Cluster { }, Configuration: redpandav1alpha1.RedpandaConfig{ AdminAPI: []redpandav1alpha1.AdminAPI{{Port: 345}}, - KafkaAPI: []redpandav1alpha1.KafkaAPI{{Port: 123}}, + KafkaAPI: []redpandav1alpha1.KafkaAPI{{Port: 123, AuthenticationMethod: "none"}}, }, Resources: redpandav1alpha1.RedpandaResourceRequirements{ ResourceRequirements: corev1.ResourceRequirements{ diff --git a/src/go/k8s/pkg/resources/testdata/Complex_struct_in_additional_configuration.golden b/src/go/k8s/pkg/resources/testdata/Complex_struct_in_additional_configuration.golden index b526e29add20..35cbc440f618 100644 --- a/src/go/k8s/pkg/resources/testdata/Complex_struct_in_additional_configuration.golden +++ b/src/go/k8s/pkg/resources/testdata/Complex_struct_in_additional_configuration.golden @@ -11,6 +11,7 @@ redpanda: - address: 0.0.0.0 port: 123 name: kafka + authentication_method: none admin: - address: 0.0.0.0 port: 345 diff --git a/src/go/k8s/pkg/resources/testdata/Primitive_object_in_additional_configuration.golden b/src/go/k8s/pkg/resources/testdata/Primitive_object_in_additional_configuration.golden index 9d2553cc470a..8ed484772d17 100644 --- a/src/go/k8s/pkg/resources/testdata/Primitive_object_in_additional_configuration.golden +++ b/src/go/k8s/pkg/resources/testdata/Primitive_object_in_additional_configuration.golden @@ -11,6 +11,7 @@ redpanda: - address: 0.0.0.0 port: 123 name: kafka + authentication_method: none admin: - address: 0.0.0.0 port: 345 diff --git a/src/go/k8s/pkg/resources/testdata/shadow_index_cache_directory.golden b/src/go/k8s/pkg/resources/testdata/shadow_index_cache_directory.golden index 2e9883fb1d63..067557f5edba 100644 --- a/src/go/k8s/pkg/resources/testdata/shadow_index_cache_directory.golden +++ b/src/go/k8s/pkg/resources/testdata/shadow_index_cache_directory.golden @@ -11,6 +11,7 @@ redpanda: - address: 0.0.0.0 port: 123 name: kafka + authentication_method: none admin: - address: 0.0.0.0 port: 345 diff --git a/src/go/k8s/tests/e2e/decommission/00-enable-downscaling.yaml b/src/go/k8s/tests/e2e/decommission/00-enable-downscaling.yaml index 3aa82a014111..e76da1e50736 100644 --- a/src/go/k8s/tests/e2e/decommission/00-enable-downscaling.yaml +++ b/src/go/k8s/tests/e2e/decommission/00-enable-downscaling.yaml @@ -2,5 +2,5 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: # Set the --allow-downscaling=true parameter in the controller manager -- command: kubectl patch deployment redpanda-controller-manager -n redpanda-system --type='json' -p='[{"op":"add", "path":"/spec/template/spec/containers/1/args/-", "value":"--allow-downscaling=true"}]' +- command: kubectl patch deployment redpanda-controller-manager -n redpanda-system --type='json' -p='[{"op":"add", "path":"/spec/template/spec/containers/0/args/-", "value":"--allow-downscaling=true"}]' - command: kubectl get deployment redpanda-controller-manager -n redpanda-system -o json diff --git a/src/go/k8s/tests/e2e/decommission/06-assert.yaml b/src/go/k8s/tests/e2e/decommission/05-assert.yaml similarity index 100% rename from src/go/k8s/tests/e2e/decommission/06-assert.yaml rename to src/go/k8s/tests/e2e/decommission/05-assert.yaml diff --git a/src/go/k8s/tests/e2e/decommission/05-restore-downscaling.yaml b/src/go/k8s/tests/e2e/decommission/05-restore-downscaling.yaml index e4d660bfe6b9..0f99149b299f 100644 --- a/src/go/k8s/tests/e2e/decommission/05-restore-downscaling.yaml +++ b/src/go/k8s/tests/e2e/decommission/05-restore-downscaling.yaml @@ -2,4 +2,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: # Downscaling will be set to the default value -- command: kubectl patch deployment redpanda-controller-manager -n redpanda-system --type='json' -p='[{"op":"remove", "path":"/spec/template/spec/containers/1/args/4"}]' +- command: "sh -c 'kustomize build ../../../config/e2e-tests | kubectl apply -f -'" \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/00-redpanda-cluster.yaml b/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/00-redpanda-cluster.yaml index 2d8ac12f8ea3..fa7f4fe06bf8 100644 --- a/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/00-redpanda-cluster.yaml +++ b/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/00-redpanda-cluster.yaml @@ -13,14 +13,16 @@ spec: limits: cpu: 1 memory: 500Mi + kafkaEnableAuthorization: true configuration: rpcServer: port: 33145 kafkaApi: - port: 9092 + authenticationMethod: sasl adminApi: - port: 9644 pandaproxyApi: - port: 8082 + authenticationMethod: http_basic developerMode: true - enableSasl: true diff --git a/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/02-produce-message.yaml b/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/02-produce-message.yaml index f2a029cbf6f5..e59c891b7ed7 100644 --- a/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/02-produce-message.yaml +++ b/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/02-produce-message.yaml @@ -13,6 +13,16 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: cluster-proxy-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: cluster-proxy-sasl + key: password command: - /bin/bash - -c @@ -21,8 +31,9 @@ spec: - | curl -v -s \ -X POST "http://cluster-proxy-0.cluster-proxy.$POD_NAMESPACE.svc.cluster.local:8082/topics/test" \ + -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" \ -H "Content-Type: application/vnd.kafka.json.v2+json" \ - -d '{"records":[{"value":"Vectorized"},{"value":"Pandaproxy"},{"value":"JSON Demo"}]}' \ + -d '{"records":[{"value":"Vectorized"},{"value":"Pandaproxy"},{"value":"JSON Demo"}]}' restartPolicy: Never backoffLimit: 6 parallelism: 1 diff --git a/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/03-consume-message.yaml b/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/03-consume-message.yaml index ba27e9c6da75..4b83b9f58ab2 100644 --- a/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/03-consume-message.yaml +++ b/src/go/k8s/tests/e2e/pandaproxy-produce-consume-sasl/03-consume-message.yaml @@ -13,6 +13,16 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: cluster-proxy-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: cluster-proxy-sasl + key: password command: - /bin/bash - -c @@ -21,7 +31,7 @@ spec: - | curl -v -s \ http://cluster-proxy-0.cluster-proxy.$POD_NAMESPACE.svc.cluster.local:8082/topics/test/partitions/0/records?offset=0\&timeout=1000\&max_bytes=100000 \ - -H "Accept: application/vnd.kafka.json.v2+json" + -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" -H "Accept: application/vnd.kafka.json.v2+json" restartPolicy: Never backoffLimit: 6 parallelism: 1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/00-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/00-assert.yaml new file mode 100644 index 000000000000..9dc365b51272 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/00-assert.yaml @@ -0,0 +1,15 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: schema-registry +status: + readyReplicas: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/00-redpanda-cluster.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/00-redpanda-cluster.yaml new file mode 100644 index 000000000000..0124e4b307c2 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/00-redpanda-cluster.yaml @@ -0,0 +1,30 @@ +apiVersion: redpanda.vectorized.io/v1alpha1 +kind: Cluster +metadata: + name: schema-registry +spec: + image: "localhost/redpanda" + version: "dev" + replicas: 1 + resources: + requests: + cpu: 100m + memory: 100Mi + limits: + cpu: 1 + memory: 100Mi + kafkaEnableAuthorization: true + configuration: + rpcServer: + port: 33145 + kafkaApi: + - port: 9092 + authenticationMethod: sasl + tls: + enabled: true + adminApi: + - port: 9644 + schemaRegistry: + port: 8081 + authenticationMethod: http_basic + developerMode: true diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/01-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/01-assert.yaml new file mode 100644 index 000000000000..ffaf4f8afbc8 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/01-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-schema +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/01-create-schema.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/01-create-schema.yaml new file mode 100644 index 000000000000..83c74b9fc7db --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/01-create-schema.yaml @@ -0,0 +1,38 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-schema +spec: + template: + spec: + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - curl + args: + - --silent + - -X + - POST + - -H + - "Content-Type: application/vnd.schemaregistry.v1+json" + - -u + - "$SCRAM_USERNAME:$SCRAM_PASSWORD" + - --data + - '{"schema": "{\"type\": \"string\"}" }' + - http://schema-registry-cluster:8081/subjects/Kafka-value/versions + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/02-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/02-assert.yaml new file mode 100644 index 000000000000..f077a8034a01 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/02-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: retrive-schema +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/02-retrieve-schema.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/02-retrieve-schema.yaml new file mode 100644 index 000000000000..7e731c3cdc6c --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/02-retrieve-schema.yaml @@ -0,0 +1,34 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: retrive-schema +spec: + template: + spec: + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - curl + args: + - --silent + - -X + - GET + - -u + - "$SCRAM_USERNAME:$SCRAM_PASSWORD" + - http://schema-registry-cluster:8081/subjects/Kafka-value/versions/1 + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/03-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/03-assert.yaml new file mode 100644 index 000000000000..644c98e0727f --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/03-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: delete-schema +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/03-delete-schema.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/03-delete-schema.yaml new file mode 100644 index 000000000000..f9070dad5ab6 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/03-delete-schema.yaml @@ -0,0 +1,34 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: delete-schema +spec: + template: + spec: + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - curl + args: + - --silent + - -X + - DELETE + - -u + - "$SCRAM_USERNAME:$SCRAM_PASSWORD" + - http://schema-registry-cluster:8081/subjects/Kafka-value/versions/1 + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/04-add-node-tls.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/04-add-node-tls.yaml new file mode 100644 index 000000000000..e7cc362d0a93 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/04-add-node-tls.yaml @@ -0,0 +1,11 @@ +apiVersion: redpanda.vectorized.io/v1alpha1 +kind: Cluster +metadata: + name: schema-registry +spec: + configuration: + schemaRegistry: + port: 8081 + authenticationMethod: http_basic + tls: + enabled: true diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/04-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/04-assert.yaml new file mode 100644 index 000000000000..7dbde59d603a --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/04-assert.yaml @@ -0,0 +1,53 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: schema-registry-schema-registry-selfsigned-issuer +status: + conditions: + - reason: IsReady + status: "True" + type: Ready + +--- + +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: schema-registry-schema-registry-root-issuer +status: + conditions: + - reason: KeyPairVerified + status: "True" + type: Ready +--- + +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: schema-registry-schema-registry-root-certificate +status: + conditions: + - reason: Ready + status: "True" + type: Ready + +--- + +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: schema-registry-schema-registry-node +status: + conditions: + - reason: Ready + status: "True" + type: Ready + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/05-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/05-assert.yaml new file mode 100644 index 000000000000..a6b5ce309f47 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/05-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-schema-with-tls +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/05-create-schema-with-tls.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/05-create-schema-with-tls.yaml new file mode 100644 index 000000000000..365099db2b90 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/05-create-schema-with-tls.yaml @@ -0,0 +1,47 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-schema-with-tls +spec: + template: + spec: + volumes: + - name: tlscert + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-node + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - /bin/bash + - -c + args: + - > + curl -vv --silent --cacert /etc/tls/certs/schema-registry/ca.crt + -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" + -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" + --data '{"schema": "{\"type\": \"string\"}" }' + https://schema-registry-cluster.$POD_NAMESPACE.svc.cluster.local.:8081/subjects/Kafka-value/versions + volumeMounts: + - mountPath: /etc/tls/certs/schema-registry + name: tlscert + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/06-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/06-assert.yaml new file mode 100644 index 000000000000..7ac234396069 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/06-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: retrieve-schema-with-tls +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/06-retrieve-schema-with-tls.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/06-retrieve-schema-with-tls.yaml new file mode 100644 index 000000000000..9d62072d4c7d --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/06-retrieve-schema-with-tls.yaml @@ -0,0 +1,45 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: retrieve-schema-with-tls +spec: + template: + spec: + volumes: + - name: tlscert + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-node + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - /bin/bash + - -c + args: + - > + curl -vv --silent --cacert /etc/tls/certs/schema-registry/ca.crt + -X GET -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" + https://schema-registry-cluster.$POD_NAMESPACE.svc.cluster.local.:8081/subjects/Kafka-value/versions/1 + volumeMounts: + - mountPath: /etc/tls/certs/schema-registry + name: tlscert + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/07-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/07-assert.yaml new file mode 100644 index 000000000000..f6de066f0260 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/07-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: delete-schema-with-tls +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/07-delete-schema-with-tls.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/07-delete-schema-with-tls.yaml new file mode 100644 index 000000000000..47bcabe8f350 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/07-delete-schema-with-tls.yaml @@ -0,0 +1,45 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: delete-schema-with-tls +spec: + template: + spec: + volumes: + - name: tlscert + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-node + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - /bin/bash + - -c + args: + - > + curl -vv --silent --cacert /etc/tls/certs/schema-registry/ca.crt + -X DELETE -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" + https://schema-registry-cluster.$POD_NAMESPACE.svc.cluster.local.:8081/subjects/Kafka-value/versions/1 + volumeMounts: + - mountPath: /etc/tls/certs/schema-registry + name: tlscert + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/08-add-client-tls.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/08-add-client-tls.yaml new file mode 100644 index 000000000000..9529dbcc4ba3 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/08-add-client-tls.yaml @@ -0,0 +1,12 @@ +apiVersion: redpanda.vectorized.io/v1alpha1 +kind: Cluster +metadata: + name: schema-registry +spec: + configuration: + schemaRegistry: + port: 8081 + authenticationMethod: http_basic + tls: + enabled: true + requireClientAuth: true diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/08-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/08-assert.yaml new file mode 100644 index 000000000000..7081a7b90eb0 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/08-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: schema-registry-schema-registry-client +status: + conditions: + - reason: Ready + status: "True" + type: Ready + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/09-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/09-assert.yaml new file mode 100644 index 000000000000..f549b234d9d4 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/09-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-schema-with-client-tls +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/09-create-schema-with-client-tls.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/09-create-schema-with-client-tls.yaml new file mode 100644 index 000000000000..0b4d3fdc780e --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/09-create-schema-with-client-tls.yaml @@ -0,0 +1,56 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: create-schema-with-client-tls +spec: + template: + spec: + volumes: + - name: tlscert + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-client + - name: tlscertca + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-node + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - /bin/bash + - -c + args: + - > + curl -vv --silent + --cacert /etc/tls/certs/schema-registry/ca/ca.crt + --cert /etc/tls/certs/schema-registry/tls.crt + --key /etc/tls/certs/schema-registry/tls.key + -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" + -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" + --data '{"schema": "{\"type\": \"string\"}" }' + https://schema-registry-cluster.$POD_NAMESPACE.svc.cluster.local.:8081/subjects/Kafka-value/versions + volumeMounts: + - mountPath: /etc/tls/certs/schema-registry + name: tlscert + - mountPath: /etc/tls/certs/schema-registry/ca + name: tlscertca + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/10-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/10-assert.yaml new file mode 100644 index 000000000000..0cfcaefaa8bd --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/10-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: retrieve-schema-with-client-tls +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/10-retrieve-schema.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/10-retrieve-schema.yaml new file mode 100644 index 000000000000..9d90520363c1 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/10-retrieve-schema.yaml @@ -0,0 +1,55 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: retrieve-schema-with-client-tls +spec: + template: + spec: + volumes: + - name: tlscert + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-client + - name: tlscertca + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-node + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - /bin/bash + - -c + args: + - > + curl -vv --silent + --cacert /etc/tls/certs/schema-registry/ca.crt + --cert /etc/tls/certs/schema-registry/tls.crt + --key /etc/tls/certs/schema-registry/tls.key + -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" + -X GET + https://schema-registry-cluster.$POD_NAMESPACE.svc.cluster.local.:8081/subjects/Kafka-value/versions/1 + volumeMounts: + - mountPath: /etc/tls/certs/schema-registry + name: tlscert + - mountPath: /etc/tls/certs/schema-registry/ca + name: tlscertca + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/11-assert.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/11-assert.yaml new file mode 100644 index 000000000000..e1e5aba38587 --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/11-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: delete-schema-with-client-tls +status: + conditions: + - status: "True" + type: Complete + succeeded: 1 + +--- + +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +collectors: +- type: pod + selector: app.kubernetes.io/name=redpanda + tail: -1 diff --git a/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/11-delete-schema.yaml b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/11-delete-schema.yaml new file mode 100644 index 000000000000..be0b2404b3cc --- /dev/null +++ b/src/go/k8s/tests/e2e/redpanda-schema-registry-sasl/11-delete-schema.yaml @@ -0,0 +1,55 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: delete-schema-with-client-tls +spec: + template: + spec: + volumes: + - name: tlscert + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-client + - name: tlscertca + secret: + defaultMode: 420 + secretName: schema-registry-schema-registry-node + containers: + - name: rpk + image: localhost/redpanda:dev + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SCRAM_USERNAME + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: username + - name: SCRAM_PASSWORD + valueFrom: + secretKeyRef: + name: schema-registry-schema-registry-sasl + key: password + command: + - /bin/bash + - -c + args: + - > + curl -vv --silent + --cacert /etc/tls/certs/schema-registry/ca/ca.crt + --cert /etc/tls/certs/schema-registry/tls.crt + --key /etc/tls/certs/schema-registry/tls.key + -u "$SCRAM_USERNAME:$SCRAM_PASSWORD" + -X DELETE + https://schema-registry-cluster.$POD_NAMESPACE.svc.cluster.local.:8081/subjects/Kafka-value/versions/1 + volumeMounts: + - mountPath: /etc/tls/certs/schema-registry + name: tlscert + - mountPath: /etc/tls/certs/schema-registry/ca + name: tlscertca + restartPolicy: Never + backoffLimit: 6 + parallelism: 1 + completions: 1 diff --git a/src/go/k8s/tests/e2e/update-conf-image/00-configurator.yaml b/src/go/k8s/tests/e2e/update-conf-image/00-configurator.yaml index ed57d0c32173..3afb4c715c46 100644 --- a/src/go/k8s/tests/e2e/update-conf-image/00-configurator.yaml +++ b/src/go/k8s/tests/e2e/update-conf-image/00-configurator.yaml @@ -1,6 +1,77 @@ +# Set specific configurator version - this will be reflected in all configurator containers of managed redpanda clusters (new or old) +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redpanda-controller-manager + namespace: redpanda-system +spec: + template: + spec: + containers: + - name: manager + image: localhost/redpanda-operator:dev + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" + - "--webhook-enabled=true" + - "--configurator-base-image=vectorized/configurator" + - "--configurator-tag=v22.1.3" + - "--configurator-image-pull-policy=IfNotPresent" + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 8081 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 20 + successThreshold: 1 + timeoutSeconds: 1 + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /readyz + port: 8081 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 100Mi + securityContext: + allowPrivilegeEscalation: false + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=10 + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 + imagePullPolicy: IfNotPresent + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP +--- apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: -# Set specific configurator version - this will be reflected in all configurator containers of managed redpanda clusters (new or old) -- command: kubectl patch deployment redpanda-controller-manager -n redpanda-system --type='json' -p='[{"op":"add", "path":"/spec/template/spec/containers/1/args/-", "value":"--configurator-tag=v22.1.3"}]' - command: kubectl get deployment redpanda-controller-manager -n redpanda-system -o json \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/update-conf-image/01-assert.yaml b/src/go/k8s/tests/e2e/update-conf-image/01-assert.yaml index b53df649f222..fae97ee7d939 100644 --- a/src/go/k8s/tests/e2e/update-conf-image/01-assert.yaml +++ b/src/go/k8s/tests/e2e/update-conf-image/01-assert.yaml @@ -6,9 +6,11 @@ spec: template: spec: initContainers: - - image: "vectorized/configurator:v22.1.3" + - name: redpanda-configurator + image: "vectorized/configurator:v22.1.3" containers: - - image: "localhost/redpanda:dev" + - name: redpanda + image: "localhost/redpanda:dev" status: readyReplicas: 2 diff --git a/src/go/k8s/tests/e2e/update-conf-image/02-new-configurator.yaml b/src/go/k8s/tests/e2e/update-conf-image/02-new-configurator.yaml index 8234332cf9aa..f2fade5903f7 100644 --- a/src/go/k8s/tests/e2e/update-conf-image/02-new-configurator.yaml +++ b/src/go/k8s/tests/e2e/update-conf-image/02-new-configurator.yaml @@ -1,5 +1,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: -# Configurator version will become default (latest) and all redpanda configurators (one here) get updated to latest -- command: kubectl patch deployment redpanda-controller-manager -n redpanda-system --type='json' -p='[{"op":"remove", "path":"/spec/template/spec/containers/1/args/4"}]' \ No newline at end of file +- command: "sh -c 'kustomize build ../../../config/e2e-tests | kubectl apply -f -'" \ No newline at end of file diff --git a/src/go/k8s/tests/e2e/update-conf-image/03-assert.yaml b/src/go/k8s/tests/e2e/update-conf-image/03-assert.yaml index 535108ce8182..e95e1a9a01ee 100644 --- a/src/go/k8s/tests/e2e/update-conf-image/03-assert.yaml +++ b/src/go/k8s/tests/e2e/update-conf-image/03-assert.yaml @@ -6,7 +6,11 @@ spec: template: spec: initContainers: - - image: "vectorized/configurator:latest" + - name: redpanda-configurator + image: "localhost/configurator:dev" + containers: + - name: redpanda + image: "localhost/redpanda:dev" status: readyReplicas: 2 @@ -19,7 +23,7 @@ metadata: spec: initContainers: - name: redpanda-configurator - image: "vectorized/configurator:latest" + image: "localhost/configurator:dev" status: phase: "Running" @@ -29,6 +33,10 @@ apiVersion: v1 kind: Pod metadata: name: update-image-cluster-1 +spec: + initContainers: + - name: redpanda-configurator + image: "localhost/configurator:dev" status: phase: "Running" diff --git a/src/go/rpk/pkg/cli/cmd/redpanda/start.go b/src/go/rpk/pkg/cli/cmd/redpanda/start.go index e8ac8b02cf13..032affa85430 100644 --- a/src/go/rpk/pkg/cli/cmd/redpanda/start.go +++ b/src/go/rpk/pkg/cli/cmd/redpanda/start.go @@ -229,7 +229,7 @@ func NewStartCommand(fs afero.Fs, launcher rp.Launcher) *cobra.Command { ",", ), ) - proxyAPI, err := parseNamedAddresses( + proxyAPI, err := parseNamedAuthNAddresses( proxyAddr, config.DefaultProxyPort, ) @@ -250,7 +250,7 @@ func NewStartCommand(fs afero.Fs, launcher rp.Launcher) *cobra.Command { ",", ), ) - schemaRegAPI, err := parseNamedAddresses( + schemaRegAPI, err := parseNamedAuthNAddresses( schemaRegAddr, config.DefaultSchemaRegPort, ) diff --git a/src/go/rpk/pkg/config/schema.go b/src/go/rpk/pkg/config/schema.go index 39a9682af521..bb315a2c2a77 100644 --- a/src/go/rpk/pkg/config/schema.go +++ b/src/go/rpk/pkg/config/schema.go @@ -75,16 +75,16 @@ type RedpandaNodeConfig struct { } type Pandaproxy struct { - PandaproxyAPI []NamedSocketAddress `yaml:"pandaproxy_api,omitempty" json:"pandaproxy_api,omitempty"` - PandaproxyAPITLS []ServerTLS `yaml:"pandaproxy_api_tls,omitempty" json:"pandaproxy_api_tls,omitempty"` - AdvertisedPandaproxyAPI []NamedSocketAddress `yaml:"advertised_pandaproxy_api,omitempty" json:"advertised_pandaproxy_api,omitempty"` - Other map[string]interface{} `yaml:",inline"` + PandaproxyAPI []NamedAuthNSocketAddress `yaml:"pandaproxy_api,omitempty" json:"pandaproxy_api,omitempty"` + PandaproxyAPITLS []ServerTLS `yaml:"pandaproxy_api_tls,omitempty" json:"pandaproxy_api_tls,omitempty"` + AdvertisedPandaproxyAPI []NamedSocketAddress `yaml:"advertised_pandaproxy_api,omitempty" json:"advertised_pandaproxy_api,omitempty"` + Other map[string]interface{} `yaml:",inline"` } type SchemaRegistry struct { - SchemaRegistryAPI []NamedSocketAddress `yaml:"schema_registry_api,omitempty" json:"schema_registry_api,omitempty"` - SchemaRegistryAPITLS []ServerTLS `yaml:"schema_registry_api_tls,omitempty" json:"schema_registry_api_tls,omitempty"` - SchemaRegistryReplicationFactor *int `yaml:"schema_registry_replication_factor,omitempty" json:"schema_registry_replication_factor,omitempty"` + SchemaRegistryAPI []NamedAuthNSocketAddress `yaml:"schema_registry_api,omitempty" json:"schema_registry_api,omitempty"` + SchemaRegistryAPITLS []ServerTLS `yaml:"schema_registry_api_tls,omitempty" json:"schema_registry_api_tls,omitempty"` + SchemaRegistryReplicationFactor *int `yaml:"schema_registry_replication_factor,omitempty" json:"schema_registry_replication_factor,omitempty"` } type KafkaClient struct { diff --git a/src/go/rpk/pkg/config/weak.go b/src/go/rpk/pkg/config/weak.go index 3da8c6e687ae..96618d11d6f2 100644 --- a/src/go/rpk/pkg/config/weak.go +++ b/src/go/rpk/pkg/config/weak.go @@ -466,10 +466,10 @@ func (r *RpkAdminAPI) UnmarshalYAML(n *yaml.Node) error { func (p *Pandaproxy) UnmarshalYAML(n *yaml.Node) error { var internal struct { - PandaproxyAPI namedSocketAddresses `yaml:"pandaproxy_api"` - PandaproxyAPITLS serverTLSArray `yaml:"pandaproxy_api_tls"` - AdvertisedPandaproxyAPI namedSocketAddresses `yaml:"advertised_pandaproxy_api"` - Other map[string]interface{} `yaml:",inline"` + PandaproxyAPI namedAuthNSocketAddresses `yaml:"pandaproxy_api"` + PandaproxyAPITLS serverTLSArray `yaml:"pandaproxy_api_tls"` + AdvertisedPandaproxyAPI namedSocketAddresses `yaml:"advertised_pandaproxy_api"` + Other map[string]interface{} `yaml:",inline"` } if err := n.Decode(&internal); err != nil { return err @@ -504,9 +504,9 @@ func (k *KafkaClient) UnmarshalYAML(n *yaml.Node) error { func (s *SchemaRegistry) UnmarshalYAML(n *yaml.Node) error { var internal struct { - SchemaRegistryAPI namedSocketAddresses `yaml:"schema_registry_api"` - SchemaRegistryAPITLS serverTLSArray `yaml:"schema_registry_api_tls"` - SchemaRegistryReplicationFactor *weakInt `yaml:"schema_registry_replication_factor"` + SchemaRegistryAPI namedAuthNSocketAddresses `yaml:"schema_registry_api"` + SchemaRegistryAPITLS serverTLSArray `yaml:"schema_registry_api_tls"` + SchemaRegistryReplicationFactor *weakInt `yaml:"schema_registry_replication_factor"` } if err := n.Decode(&internal); err != nil { diff --git a/src/go/rpk/pkg/config/weak_test.go b/src/go/rpk/pkg/config/weak_test.go index 1e59b0f69072..c5ab8b4d989e 100644 --- a/src/go/rpk/pkg/config/weak_test.go +++ b/src/go/rpk/pkg/config/weak_test.go @@ -1006,9 +1006,9 @@ rpk: }, }, Pandaproxy: &Pandaproxy{ - PandaproxyAPI: []NamedSocketAddress{ - {"0.0.0.0", 8082, "internal"}, - {"0.0.0.0", 8083, "external"}, + PandaproxyAPI: []NamedAuthNSocketAddress{ + {"0.0.0.0", 8082, "internal", nil}, + {"0.0.0.0", 8083, "external", nil}, }, PandaproxyAPITLS: []ServerTLS{ {Name: "external", Enabled: false, TruststoreFile: "truststore_file"}, @@ -1036,9 +1036,9 @@ rpk: }, }, SchemaRegistry: &SchemaRegistry{ - SchemaRegistryAPI: []NamedSocketAddress{ - {"0.0.0.0", 8081, "internal"}, - {"0.0.0.0", 18081, "external"}, + SchemaRegistryAPI: []NamedAuthNSocketAddress{ + {"0.0.0.0", 8081, "internal", nil}, + {"0.0.0.0", 18081, "external", nil}, }, SchemaRegistryAPITLS: []ServerTLS{ {Name: "external", Enabled: false}, @@ -1330,9 +1330,9 @@ rpk: }, }, Pandaproxy: &Pandaproxy{ - PandaproxyAPI: []NamedSocketAddress{ - {"0.0.0.0", 8082, "internal"}, - {"0.0.0.0", 8083, "external"}, + PandaproxyAPI: []NamedAuthNSocketAddress{ + {"0.0.0.0", 8082, "internal", nil}, + {"0.0.0.0", 8083, "external", nil}, }, PandaproxyAPITLS: []ServerTLS{ {Name: "external", Enabled: false, TruststoreFile: "truststore_file"}, @@ -1360,9 +1360,9 @@ rpk: }, }, SchemaRegistry: &SchemaRegistry{ - SchemaRegistryAPI: []NamedSocketAddress{ - {"0.0.0.0", 8081, "internal"}, - {"0.0.0.0", 18081, "external"}, + SchemaRegistryAPI: []NamedAuthNSocketAddress{ + {"0.0.0.0", 8081, "internal", nil}, + {"0.0.0.0", 18081, "external", nil}, }, SchemaRegistryAPITLS: []ServerTLS{ {Name: "external", Enabled: false},