Skip to content

Commit

Permalink
Issue 280: Read InfluxDB credentials from a secret (#563)
Browse files Browse the repository at this point in the history
* Adding support for configuring influxdb secret

Signed-off-by: anishakj <[email protected]>

* passing influxdb secret mount path as an env variable

Signed-off-by: anishakj <[email protected]>

* incorporating review comments

Signed-off-by: anishakj <[email protected]>

* Fixing the unit tests

Signed-off-by: anishakj <[email protected]>

* updating crd for end to end tests

Signed-off-by: anishakj <[email protected]>
  • Loading branch information
anishakj authored Jul 26, 2021
1 parent 8d45948 commit d712947
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 6 deletions.
18 changes: 18 additions & 0 deletions deploy/crds/pravega.pravega.io_pravegaclusters_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2186,6 +2186,24 @@ spec:
repository:
type: string
type: object
influxDBSecret:
description: InfluxDB Secret specifies the secret name containing
credentials and mount path volume that has to be configured
in controller and segmentstore pods
properties:
mountPath:
description: Path to the volume where the secret will be mounted
This value is considered only when the secret is provided
If this value is provided, the secret is mounted to specified
Volume else default mount path is used.
type: string
secret:
description: Secret specifies the name of Secret which needs
to be configured
type: string
required:
- secret
type: object
longtermStorage:
description: LongTermStorage is the configuration of Pravega's
tier 2 storage. If no configuration is provided, it will assume
Expand Down
1 change: 1 addition & 0 deletions doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ This document explains how to configure Pravega
* [Configuring Service and Sts Names](service-sts-name-configuration.md)
* [Enable AuthHandlers](auth-handlers.md)
* [Init Containers Usage](init-containers.md)
* [Enable InfluxDB Authentication](influxdb-auth.md)
27 changes: 27 additions & 0 deletions doc/influxdb-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Enable InfluxDB Authentication

Operator supports passing influxdb credentials as secret. It is the recommended approach rather than passing username/password as part of Pravega options.

Steps to configure influxdb authentication are as follows:

1. Create a secret for basic authentication. Below is the sample yaml file

```
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin
password: t0p-Secret
```
2. Modify the Pravega manifest to include the secret name for influxdb

```
influxDBSecret:
name: "secret-basic-auth"
path: "/etc/secret"
```

3. Once Pravega is deployed, secret will be mounted in `/etc/secret` for controller and segment store pods. If the path is not mentioned, `/etc/influxdb-secret-volume` will be used as default path.
38 changes: 38 additions & 0 deletions pkg/apis/pravega/v1beta1/pravega.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const (

// DefaultSegmentStoreLimitMemory is the default memory limit for Pravega
DefaultSegmentStoreLimitMemory = "2Gi"

// DefaultInfluxDBSecretMountDir is the default mountpath of influxdb secret
DefaultInfluxDBSecretMountDir = "/etc/influxdb-secret-volume"
)

// PravegaSpec defines the configuration of Pravega
Expand Down Expand Up @@ -228,6 +231,10 @@ type PravegaSpec struct {

// Details of authplugin to be copied into pravega controller
AuthImplementations *AuthImplementationSpec `json:"authImplementations,omitempty"`

// InfluxDB Secret specifies the secret name containing credentials and mount path volume
// that has to be configured in controller and segmentstore pods
InfluxDBSecret *InfluxDBSecret `json:"influxDBSecret,omitempty"`
}

func (s *PravegaSpec) withDefaults() (changed bool) {
Expand Down Expand Up @@ -325,6 +332,14 @@ func (s *PravegaSpec) withDefaults() (changed bool) {
changed = true
}

if s.InfluxDBSecret == nil {
changed = true
s.InfluxDBSecret = &InfluxDBSecret{}
}

if s.InfluxDBSecret.withDefaults() {
changed = true
}
if s.ControllerServiceAnnotations == nil {
changed = true
s.ControllerServiceAnnotations = map[string]string{}
Expand Down Expand Up @@ -389,6 +404,29 @@ func (s *SegmentStoreSecret) withDefaults() (changed bool) {
return changed
}

// InfluxDBSecret defines the configuration of the secret for controller and
// segmentstore
type InfluxDBSecret struct {
// Secret specifies the name of Secret which needs to be configured
Secret string `json:"secret"`

// Path to the volume where the secret will be mounted
// This value is considered only when the secret is provided
// If this value is provided, the secret is mounted to specified Volume
// else default mount path is used.
// +optional
MountPath string `json:"mountPath"`
}

func (s *InfluxDBSecret) withDefaults() (changed bool) {
if s.Secret != "" && s.MountPath == "" {
s.MountPath = DefaultInfluxDBSecretMountDir
changed = true
}

return changed
}

func (s *ImageSpec) withDefaults() (changed bool) {
if s.Repository == "" {
changed = true
Expand Down
21 changes: 21 additions & 0 deletions pkg/apis/pravega/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions pkg/apis/pravega/v1beta1/zz_generated_deepcopy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ var _ = Describe("PravegaCluster DeepCopy", func() {
Secret: "seg-secret",
MountPath: "",
},

InfluxDBSecret: &v1beta1.InfluxDBSecret{
Secret: "influx-secret",
MountPath: "",
},
SegmentStoreInitContainers: []v1.Container{
v1.Container{
Name: "testing",
Expand Down Expand Up @@ -125,6 +128,7 @@ var _ = Describe("PravegaCluster DeepCopy", func() {

p2.Spec.Pravega = p1.Spec.Pravega.DeepCopy()
p2.Spec.Pravega.SegmentStoreSecret = p1.Spec.Pravega.SegmentStoreSecret.DeepCopy()
p2.Spec.Pravega.InfluxDBSecret = p1.Spec.Pravega.InfluxDBSecret.DeepCopy()
p2.Spec.Pravega.AuthImplementations = p1.Spec.Pravega.AuthImplementations.DeepCopy()
p2.Spec.Pravega.AuthImplementations.AuthHandlers[0] = *p1.Spec.Pravega.AuthImplementations.AuthHandlers[0].DeepCopy()

Expand Down Expand Up @@ -244,10 +248,18 @@ var _ = Describe("PravegaCluster DeepCopy", func() {
p1.Spec.ExternalAccess = nil
Ω(p1.Spec.ExternalAccess.DeepCopy()).Should(BeNil())
})
It("checking for nil TLS Sttic", func() {
It("checking for nil TLS Static", func() {
p1.Spec.TLS.Static = nil
Ω(p1.Spec.TLS.Static.DeepCopy()).Should(BeNil())
})
It("checking for nil InfluxDBsecret", func() {
p1.Spec.Pravega.InfluxDBSecret = nil
Ω(p1.Spec.Pravega.InfluxDBSecret.DeepCopy()).Should(BeNil())
})
It("checking for nil SegmentStore secret", func() {
p1.Spec.Pravega.SegmentStoreSecret = nil
Ω(p1.Spec.Pravega.SegmentStoreSecret.DeepCopy()).Should(BeNil())
})
It("checking for nil Pravega LongTermStorage", func() {
p1.Spec.Pravega.LongTermStorage = nil
Ω(p1.Spec.Pravega.LongTermStorage.DeepCopy()).Should(BeNil())
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/pravega/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ const (
ssAuthVolumeName = "ss-auth-secret"
controllerAuthMountDir = "/etc/controller-auth-volume"
ssAuthMountDir = "/etc/ss-auth-volume"
influxDBSecretVolumeName = "influxdb-secret"
)
15 changes: 15 additions & 0 deletions pkg/controller/pravega/pravega_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ func makeControllerPodSpec(p *api.PravegaCluster) *corev1.PodSpec {
configureControllerTLSSecrets(podSpec, p)
configureAuthSecrets(podSpec, p)
configureControllerAuthSecrets(podSpec, p)
configureControllerInfluxDBSecrets(podSpec, p)
return podSpec
}

Expand All @@ -276,6 +277,20 @@ func configureControllerAuthSecrets(podSpec *corev1.PodSpec, p *api.PravegaClust
}
}

func configureControllerInfluxDBSecrets(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
if p.Spec.Pravega.InfluxDBSecret.Secret != "" {
addSecretVolumeWithMount(podSpec, p, influxDBSecretVolumeName, p.Spec.Pravega.InfluxDBSecret.Secret,
influxDBSecretVolumeName, p.Spec.Pravega.InfluxDBSecret.MountPath)

podSpec.Containers[0].Env = []corev1.EnvVar{
{
Name: "INFLUX_DB_SECRET_MOUNT_PATH",
Value: p.Spec.Pravega.InfluxDBSecret.MountPath,
},
}
}
}

func addSecretVolumeWithMount(podSpec *corev1.PodSpec, p *api.PravegaCluster,
volumeName string, secretName string,
mountName string, mountDir string) {
Expand Down
9 changes: 9 additions & 0 deletions pkg/controller/pravega/pravega_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ var _ = Describe("Controller", func() {
ControllerPodAnnotations: annotationsMap,
SegmentStoreServiceAnnotations: annotationsMap,
SegmentStorePodLabels: annotationsMap,
InfluxDBSecret: &v1beta1.InfluxDBSecret{
Secret: "influxdb-secret",
MountPath: "",
},
Image: &v1beta1.ImageSpec{
Repository: "bar/pravega",
},
Expand Down Expand Up @@ -181,6 +185,11 @@ var _ = Describe("Controller", func() {

})

It("should have VolumeMounts created for influxdb secret", func() {
deploy := pravega.MakeControllerPodTemplate(p)
mounthostpath := deploy.Spec.Containers[0].VolumeMounts[9].MountPath
Ω(mounthostpath).Should(Equal("/etc/influxdb-secret-volume"))
})
It("should create the service", func() {
svc := pravega.MakeControllerService(p)
Ω(svc.Spec.Type).To(Equal(corev1.ServiceTypeClusterIP))
Expand Down
27 changes: 27 additions & 0 deletions pkg/controller/pravega/pravega_segmentstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func MakeSegmentStorePodTemplate(p *api.PravegaCluster) corev1.PodTemplateSpec {
func makeSegmentstorePodSpec(p *api.PravegaCluster) corev1.PodSpec {
configMapName := strings.TrimSpace(p.Spec.Pravega.SegmentStoreEnvVars)
secret := p.Spec.Pravega.SegmentStoreSecret

environment := []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
Expand Down Expand Up @@ -263,6 +264,8 @@ func makeSegmentstorePodSpec(p *api.PravegaCluster) corev1.PodSpec {

configureSegmentstoreAuthSecret(&podSpec, p)

configureInfluxDBSecret(&podSpec, p)

return podSpec
}

Expand Down Expand Up @@ -471,6 +474,30 @@ func configureCaBundleSecret(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
}
}

func configureInfluxDBSecret(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
if p.Spec.Pravega.InfluxDBSecret.Secret != "" {
vol := corev1.Volume{
Name: influxDBSecretVolumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: p.Spec.Pravega.InfluxDBSecret.Secret,
},
},
}
podSpec.Volumes = append(podSpec.Volumes, vol)

podSpec.Containers[0].VolumeMounts = append(podSpec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: influxDBSecretVolumeName,
MountPath: p.Spec.Pravega.InfluxDBSecret.MountPath,
})

podSpec.Containers[0].Env = append(podSpec.Containers[0].Env, corev1.EnvVar{
Name: "INFLUX_DB_SECRET_MOUNT_PATH",
Value: p.Spec.Pravega.InfluxDBSecret.MountPath,
})
}
}

func MakeSegmentStoreHeadlessService(p *api.PravegaCluster) *corev1.Service {
serviceport, _ := strconv.Atoi(p.Spec.Pravega.Options["pravegaservice.service.listener.port"])
return &corev1.Service{
Expand Down
22 changes: 18 additions & 4 deletions pkg/controller/pravega/pravega_segmentstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ var _ = Describe("PravegaSegmentstore", func() {
SegmentStorePodLabels: annotationsMap,
SegmentStorePodAnnotations: annotationsMap,
SegmentStoreEnvVars: "SEG_CONFIG_MAP",
InfluxDBSecret: &v1beta1.InfluxDBSecret{
Secret: "influxdb-secret",
MountPath: "",
},
SegmentStoreSecret: &v1beta1.SegmentStoreSecret{
Secret: "seg-secret",
MountPath: "",
Expand Down Expand Up @@ -120,8 +124,9 @@ var _ = Describe("PravegaSegmentstore", func() {
},
},
Authentication: &v1beta1.AuthenticationParameters{
Enabled: true,
PasswordAuthSecret: "authentication-secret",
Enabled: true,
PasswordAuthSecret: "authentication-secret",
SegmentStoreTokenSecret: "segment-store-secret",
},
}
p.WithDefaults()
Expand Down Expand Up @@ -187,6 +192,8 @@ var _ = Describe("PravegaSegmentstore", func() {
Ω(mounthostpath3).Should(Equal("/opt/pravega/logs"))
mounthostpath4 := sts.Spec.Template.Spec.Containers[0].VolumeMounts[4].MountPath
Ω(mounthostpath4).Should(Equal("/opt/pravega/conf/logback.xml"))
mounthostpath5 := sts.Spec.Template.Spec.Containers[0].VolumeMounts[9].MountPath
Ω(mounthostpath5).Should(Equal("/etc/influxdb-secret-volume"))
Ω(err).Should(BeNil())
})

Expand Down Expand Up @@ -315,11 +322,14 @@ var _ = Describe("PravegaSegmentstore", func() {
Ω(strings.Contains(javaOpts, "-Dpravegaservice.service.listener.port=443")).Should(BeTrue())
Ω(err).Should(BeNil())
})

It("should create a stateful set with filesystem as longtermstorage", func() {
sts := pravega.MakeSegmentStoreStatefulSet(p)
mounthostpath0 := sts.Spec.Template.Spec.Containers[0].VolumeMounts[4].MountPath
Ω(mounthostpath0).Should(Equal("/mnt/tier2"))
})
It("should set external access service type to LoadBalancer", func() {
Ω(p.Spec.ExternalAccess.Type).Should(Equal(corev1.ServiceTypeClusterIP))
})

})
})

Expand Down Expand Up @@ -362,6 +372,10 @@ var _ = Describe("PravegaSegmentstore", func() {
SegmentStoreServiceAnnotations: annotationsMap,
SegmentStorePodLabels: annotationsMap,
SegmentStoreExternalServiceType: corev1.ServiceTypeLoadBalancer,
SegmentStoreSecret: &v1beta1.SegmentStoreSecret{
Secret: "seg-secret",
MountPath: "/tmp/mount",
},
Image: &v1beta1.ImageSpec{
Repository: "bar/pravega",
},
Expand Down
18 changes: 18 additions & 0 deletions test/e2e/resources/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,24 @@ spec:
repository:
type: string
type: object
influxDBSecret:
description: InfluxDB Secret specifies the secret name containing
credentials and mount path volume that has to be configured
in controller and segmentstore pods
properties:
mountPath:
description: Path to the volume where the secret will be mounted
This value is considered only when the secret is provided
If this value is provided, the secret is mounted to specified
Volume else default mount path is used.
type: string
secret:
description: Secret specifies the name of Secret which needs
to be configured
type: string
required:
- secret
type: object
longtermStorage:
description: LongTermStorage is the configuration of Pravega's
tier 2 storage. If no configuration is provided, it will assume
Expand Down

0 comments on commit d712947

Please sign in to comment.