Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 479: Addressing Security vulnerabilities with authentication #488

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ spec:
from clients to controller and segment store See the following file
for a complete list of options: https://github.com/pravega/pravega/blob/master/documentation/src/docs/security/pravega-security-configurations.md'
properties:
controllerTokenSecret:
type: string
enabled:
description: Enabled specifies whether or not authentication is
enabled By default, authentication is not enabled
Expand All @@ -83,6 +85,8 @@ spec:
Parameters like username, password and acl optional - used only
by PasswordAuthHandler for authentication
type: string
segmentStoreTokenSecret:
type: string
type: object
bookkeeperUri:
description: BookkeeperUri specifies the hostname/IP address and port
Expand Down
2 changes: 2 additions & 0 deletions charts/pravega/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ The following table lists the configurable parameters of the pravega chart and t
| `tls` | Pravega security configuration passed to the Pravega processes | `{}` |
| `authentication.enabled` | Enable authentication to authorize client communication with Pravega | `false` |
| `authentication.passwordAuthSecret` | Name of Secret containing Password based Authentication Parameters, if authentication is enabled | |
| `authentication.segmentStoreTokenSecret` | Name of Secret containing tokenSigningkey for the ss, if authentication is enabled | |
| `authentication.controllerTokenSecret` | Name of Secret containing tokenSigningkey for controller, if authentication is enabled | |
| `zookeeperUri` | Zookeeper client service URI | `zookeeper-client:2181` |
| `bookkeeperUri` | Bookkeeper headless service URI | `bookkeeper-bookie-headless:3181` |
| `externalAccess.enabled` | Enable external access | `false` |
Expand Down
3 changes: 3 additions & 0 deletions charts/pravega/templates/pravega.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ spec:
enabled: {{ .Values.authentication.enabled }}
{{- if .Values.authentication.enabled }}
passwordAuthSecret: {{ .Values.authentication.passwordAuthSecret }}
segmentStoreTokenSecret: {{ .Values.authentication.segmentStoreTokenSecret }}
controllerTokenSecret: {{ .Values.authentication.controllerTokenSecret }}
{{- end }}

version: {{ .Values.version }}
zookeeperUri: {{ .Values.zookeeperUri }}
bookkeeperUri: {{ .Values.bookkeeperUri }}
Expand Down
4 changes: 4 additions & 0 deletions charts/pravega/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ authentication:
enabled: false
## passwordAuthSecret is ignored if authentication is disabled
passwordAuthSecret:
#segmentStoreToken is ignored if authentication is disabled
segmentStoreTokenSecret:
#controllerTokenSecret is ignored if authentication is disabled
controllerTokenSecret:

zookeeperUri: zookeeper-client:2181
bookkeeperUri: bookkeeper-bookie-headless:3181
Expand Down
4 changes: 4 additions & 0 deletions deploy/crds/pravega.pravega.io_pravegaclusters_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ spec:
from clients to controller and segment store See the following file
for a complete list of options: https://github.com/pravega/pravega/blob/master/documentation/src/docs/security/pravega-security-configurations.md'
properties:
controllerTokenSecret:
type: string
enabled:
description: Enabled specifies whether or not authentication is
enabled By default, authentication is not enabled
Expand All @@ -71,6 +73,8 @@ spec:
Parameters like username, password and acl optional - used only
by PasswordAuthHandler for authentication
type: string
segmentStoreTokenSecret:
type: string
type: object
bookkeeperUri:
description: BookkeeperUri specifies the hostname/IP address and port
Expand Down
80 changes: 80 additions & 0 deletions doc/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,83 @@ where username and password are credentials you intend to use.
Note that Pravega operator uses `/etc/auth-passwd-volume` as the mounting directory for secrets.

For more security configurations, please check [here](https://github.com/pravega/pravega/blob/master/documentation/src/docs/security/pravega-security-configurations.md).

Pravega Operator Supports Passing of Auth Parametes as Secret which are mounted as file in both Segment Store and Controller (Operator mounts these secrets in Segementstore pod it's mounted at `/etc/ss-auth-volume` and in Controller pod at `/etc/controller-auth-volume` respectively)

Note that Pravega has to use this feature and start Picking below specified values from file insted of jvm properties which it currently does.
(This is not implemented at pravega end currently)

Below is how we can create secret and expose them as file for Auth related properties:-

1. Create a File containg `controller.security.auth.delegationToken.signingKey.basis` as `delegationToken.signingKey.basis` which represent the tokensigning key used to connect to the controller:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a nit but I'm not getting what the "basis" suffix means?

Copy link
Contributor Author

@Prabhaker24 Prabhaker24 Jan 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pravega uses this suffix so I tried keeping it the same. In any case this is just a key in a secret so if pravega changes the name for this parameter we can always have the name of the key different.


Sample encrypted password file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 89 was maybe a left over from a copy paste from somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed it now.

```
$ cat controllerauthdata.txt
delegationToken.signingKey.basis: "secret"
```

2. Create a kubernetes secret with this file:

```
$ kubectl create secret generic controllertokensecret \
--from-file=./controllerauthdata.txt \
```

Ensure Secret is created:-

```
$ kubectl describe secret controllertokensecret
Name: controllertokensecret
Namespace: default
Labels: <none>
Annotations: <none>

Type: Opaque

Data
====
controllerauthdata.txt: 67 bytes

```

3. Create a File containg `autoScale.security.auth.token.signingKey.basis` as `delegationToken.signingKey.basis` which represent the tokensigning key used to connect to the Segmentstore along with other 3 values `pravega.client.auth.method`, `pravega.client.auth.token` and `controller.connect.auth.credentials.dynamic` as `controller.connect.auth.params` which contains all the 3 values in the same order seprated by semicolon:

```
$ cat segmentstoreauthdata.txt
delegationToken.signingKey.basis: "secret"
controller.connect.auth.params: {method};{token};{dynamic}
```
4. Create a kubernetes secret with this file:

```
$ kubectl create secret generic sstokensecret \
--from-file=./segmentstoreauthdata.txt \
```
Ensure Secret is created:-

```
$ kubectl describe secret sstokensecret
Name: sstokensecret
Namespace: default
Labels: <none>
Annotations: <none>

Type: Opaque

Data
====
segmentstoreauthdata.txt: 106 bytes

```

5. Use these secrets instead of specifying the values in the option:-

```
spec:
authentication:
enabled: true
passwordAuthSecret: password-auth
segmentStoreTokenSecret: sstokensecret
controllerTokenSecret: controllertokensecret
```
6 changes: 6 additions & 0 deletions pkg/apis/pravega/v1beta1/pravegacluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ type AuthenticationParameters struct {
// name of Secret containing Password based Authentication Parameters like username, password and acl
// optional - used only by PasswordAuthHandler for authentication
PasswordAuthSecret string `json:"passwordAuthSecret,omitempty"`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For integration purposes, there needs to be a clear description of how to create the two secrets.
I can see through the code the format of the secret is straight forward, with one having one entry which is just a random string; and the other having two entries, one being the same random string, and one being a base64 encoded string of the admin/password, to be used with the password handler.

It won't be obvious to the common dweller though. :)

Having clear couple kubectl commands in the README that show exactly how to generate these 2 secrets is crucial so integrators know how to leverage this welcome enhancement.

Copy link
Contributor Author

@Prabhaker24 Prabhaker24 Jan 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sarlaccpit, I have added documentation in the auth section of our documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the auth.md is very useful and detailed. It will be crucial information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sarlaccpit .

//name of secret containg TokenSigningKey
ControllerTokenSecret string `json:"controllerTokenSecret,omitempty"`

//name of secret containg TokenSigningKey and AuthToken
SegmentStoreTokenSecret string `json:"segmentStoreTokenSecret,omitempty"`
}

func (ap *AuthenticationParameters) IsEnabled() bool {
Expand Down
34 changes: 19 additions & 15 deletions pkg/controller/pravega/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@
package pravega

const (
cacheVolumeName = "cache"
cacheVolumeMountPoint = "/tmp/pravega/cache"
ltsFileMountPoint = "/mnt/tier2"
ltsVolumeName = "tier2"
segmentStoreKind = "pravega-segmentstore"
ssSecretVolumeName = "ss-secret"
tlsVolumeName = "tls-secret"
tlsMountDir = "/etc/secret-volume"
caBundleVolumeName = "ca-bundle"
caBundleMountDir = "/etc/secret-volume/ca-bundle"
heapDumpName = "heap-dump"
heapDumpDir = "/tmp/dumpfile/heap"
authVolumeName = "auth-passwd-secret"
authMountDir = "/etc/auth-passwd-volume"
defaultTokenSigningKey = "secret"
cacheVolumeName = "cache"
cacheVolumeMountPoint = "/tmp/pravega/cache"
ltsFileMountPoint = "/mnt/tier2"
ltsVolumeName = "tier2"
segmentStoreKind = "pravega-segmentstore"
ssSecretVolumeName = "ss-secret"
tlsVolumeName = "tls-secret"
tlsMountDir = "/etc/secret-volume"
caBundleVolumeName = "ca-bundle"
caBundleMountDir = "/etc/secret-volume/ca-bundle"
heapDumpName = "heap-dump"
heapDumpDir = "/tmp/dumpfile/heap"
authVolumeName = "auth-passwd-secret"
authMountDir = "/etc/auth-passwd-volume"
defaultTokenSigningKey = "secret"
controllerAuthVolumeName = "controller-auth-secret"
ssAuthVolumeName = "ss-auth-secret"
controllerAuthMountDir = "/etc/controller-auth-volume"
ssAuthMountDir = "/etc/ss-auth-volume"
)
8 changes: 8 additions & 0 deletions pkg/controller/pravega/pravega_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func makeControllerPodSpec(p *api.PravegaCluster) *corev1.PodSpec {

configureControllerTLSSecrets(podSpec, p)
configureAuthSecrets(podSpec, p)
configureControllerAuthSecrets(podSpec, p)
return podSpec
}

Expand All @@ -158,6 +159,13 @@ func configureAuthSecrets(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
}
}

func configureControllerAuthSecrets(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
if p.Spec.Authentication.IsEnabled() && p.Spec.Authentication.ControllerTokenSecret != "" {
addSecretVolumeWithMount(podSpec, p, controllerAuthVolumeName, p.Spec.Authentication.ControllerTokenSecret,
controllerAuthVolumeName, controllerAuthMountDir)
}
}

func addSecretVolumeWithMount(podSpec *corev1.PodSpec, p *api.PravegaCluster,
volumeName string, secretName string,
mountName string, mountDir string) {
Expand Down
10 changes: 6 additions & 4 deletions pkg/controller/pravega/pravega_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ var _ = Describe("Controller", func() {
},
},
Authentication: &v1beta1.AuthenticationParameters{
Enabled: true,
PasswordAuthSecret: "authentication-secret",
Enabled: true,
PasswordAuthSecret: "authentication-secret",
ControllerTokenSecret: "controllerauthsecret",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, maybe controllerauthsecret --> controllerauth-secret ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed it.

},
}
p.WithDefaults()
Expand Down Expand Up @@ -219,8 +220,9 @@ var _ = Describe("Controller", func() {
},
},
Authentication: &v1beta1.AuthenticationParameters{
Enabled: true,
PasswordAuthSecret: "authentication-secret",
Enabled: true,
PasswordAuthSecret: "authentication-secret",
ControllerTokenSecret: "controllerauthsecret",
Prabhaker24 marked this conversation as resolved.
Show resolved Hide resolved
},
}
p.WithDefaults()
Expand Down
21 changes: 21 additions & 0 deletions pkg/controller/pravega/pravega_segmentstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ func makeSegmentstorePodSpec(p *api.PravegaCluster) corev1.PodSpec {

configureLTSFilesystem(&podSpec, p.Spec.Pravega)

configureSegmentstoreAuthSecret(&podSpec, p)

return podSpec
}

Expand Down Expand Up @@ -378,6 +380,25 @@ func configureSegmentstoreTLSSecret(podSpec *corev1.PodSpec, p *api.PravegaClust
}
}

func configureSegmentstoreAuthSecret(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
if p.Spec.Authentication.SegmentStoreTokenSecret != "" {
vol := corev1.Volume{
Name: ssAuthVolumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: p.Spec.Authentication.SegmentStoreTokenSecret,
},
},
}
podSpec.Volumes = append(podSpec.Volumes, vol)

podSpec.Containers[0].VolumeMounts = append(podSpec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: ssAuthVolumeName,
MountPath: ssAuthMountDir,
})
}
}

func configureCaBundleSecret(podSpec *corev1.PodSpec, p *api.PravegaCluster) {
if p.Spec.TLS.IsCaBundlePresent() {
vol := corev1.Volume{
Expand Down
5 changes: 3 additions & 2 deletions pkg/controller/pravega/pravega_segmentstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,9 @@ var _ = Describe("PravegaSegmentstore", func() {
},
},
Authentication: &v1beta1.AuthenticationParameters{
Enabled: true,
PasswordAuthSecret: "authentication-secret",
Enabled: true,
PasswordAuthSecret: "authentication-secret",
SegmentStoreTokenSecret: "authentication-secret",
},
}
p.WithDefaults()
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/resources/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ spec:
from clients to controller and segment store See the following file
for a complete list of options: https://github.com/pravega/pravega/blob/master/documentation/src/docs/security/pravega-security-configurations.md'
properties:
controllerTokenSecret:
description: name of secret containg TokenSigningKey
type: string
enabled:
description: Enabled specifies whether or not authentication is
enabled By default, authentication is not enabled
Expand All @@ -71,6 +74,9 @@ spec:
Parameters like username, password and acl optional - used only
by PasswordAuthHandler for authentication
type: string
segmentStoreTokenSecret:
description: name of secret containg TokenSigningKey and AuthToken
type: string
type: object
bookkeeperUri:
description: BookkeeperUri specifies the hostname/IP address and port
Expand Down
4 changes: 4 additions & 0 deletions tools/manifest_files/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ spec:
from clients to controller and segment store See the following file
for a complete list of options: https://github.com/pravega/pravega/blob/master/documentation/src/docs/security/pravega-security-configurations.md'
properties:
controllerTokenSecret:
type: string
enabled:
description: Enabled specifies whether or not authentication is
enabled By default, authentication is not enabled
Expand All @@ -80,6 +82,8 @@ spec:
Parameters like username, password and acl optional - used only
by PasswordAuthHandler for authentication
type: string
segmentStoreTokenSecret:
type: string
type: object
bookkeeperUri:
description: BookkeeperUri specifies the hostname/IP address and port
Expand Down