Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e21b1e7
feat(oauth-properties): add spec to specify oauth properties as confi…
tthvo Aug 17, 2022
ef7183a
docs(oauth): add docs on oauth properties spec
tthvo Aug 18, 2022
07c11ee
test(resources): add resources for testing cryostat with oauth proper…
tthvo Aug 18, 2022
028c7ca
test(oauth): add unit tests for present oauth properties
tthvo Aug 18, 2022
335e669
chore(test): rename test oauth-props configmap
tthvo Aug 18, 2022
a63ba6b
fix(tests): fix failed unit tests for oauth props
tthvo Aug 18, 2022
dd62b11
fix(manifests): update markers, manifests and bundle
tthvo Aug 18, 2022
715c8a7
fix(crd): rename prefix oauth to auth for permission mapping
tthvo Aug 18, 2022
8689c9d
docs(auth): update docs on permission mappings
tthvo Aug 18, 2022
d3bbbd6
docs(config): fix typo
tthvo Aug 18, 2022
7774e28
docs(config): fix report example yaml
tthvo Aug 18, 2022
4e47149
fix(apis): update descriptions for authProperties
tthvo Aug 18, 2022
9b5d94b
docs(config): update config docs
tthvo Aug 18, 2022
3495ebd
fix(apis): add full display name for auth properties
tthvo Aug 18, 2022
3113d70
fix(apis): make authProperties as pointer
tthvo Aug 18, 2022
7143ec9
docs(config): update config docs
tthvo Aug 18, 2022
8df56bc
fix(test): update methods name and context descriptions
tthvo Aug 18, 2022
4bd844b
fix(tests): use ConsistsOf to compare slices
tthvo Aug 18, 2022
6a69dea
fix(crds): refine authorization spec field
tthvo Aug 22, 2022
0232392
fix(crds): fix description typo
tthvo Aug 22, 2022
fb5f8c8
docs(config): update config docs
tthvo Aug 22, 2022
6b81673
fix(tests): fix test resource definition
tthvo Aug 22, 2022
956d338
tests(auth): update auth-props to check env vars on openshift
tthvo Aug 22, 2022
7a47f00
temp: modify default-oauth
tthvo Aug 23, 2022
44db0d0
fix(apis): update descriptions for CR specs
tthvo Aug 24, 2022
9ef15d6
fix(auth-props): only configure auth properties on Openshift
tthvo Aug 24, 2022
876a2b9
docs(config): update docs on custom auth properties
tthvo Aug 24, 2022
f59045b
fix(apis): add xdescriptor for auth filename, fix auth spec field typ…
tthvo Aug 24, 2022
0a803f7
fix(oauth): use default oauth-client-role as base
tthvo Aug 25, 2022
6468bc9
fix(rbac): update default oauth-client cluster role
tthvo Aug 25, 2022
f5a91df
docs(config): mention escalation issue if using secret in permission …
tthvo Aug 25, 2022
270ce84
fix(rbac): update base oauth-client role
tthvo Aug 26, 2022
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
13 changes: 13 additions & 0 deletions api/v1beta1/cryostat_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ type CryostatSpec struct {
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
Resources ResourceConfigList `json:"resources,omitempty"`
// A permission mapping from Cryostat resources to Kubernetes resources used for authorization.
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
AuthProperties AuthPropertiesConfigMap `json:"authProperties,omitempty"`
Comment thread
tthvo marked this conversation as resolved.
Outdated
}

type ResourceConfigList struct {
Expand Down Expand Up @@ -402,3 +406,12 @@ type TemplateConfigMap struct {
// Filename within config map containing the template file
Filename string `json:"filename"`
}

// A ConfigMap containing a permission mapping between Cryostat resources to Kubernetes resources.
type AuthPropertiesConfigMap struct {
// Name of config map in the local namespace.
// +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:io.kubernetes:ConfigMap"}
ConfigMapName string `json:"configMapName"`
// Filename within config map containing the resource mapping.
Filename string `json:"filename"`
}
16 changes: 16 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

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

9 changes: 9 additions & 0 deletions bundle/manifests/cryostat-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ spec:
name: ""
version: v1
specDescriptors:
- description: A permission mapping from Cryostat resources to Kubernetes resources
used for authorization.
displayName: Auth Properties
path: authProperties
- description: Name of config map in the local namespace.
displayName: Config Map Name
path: authProperties.configMapName
x-descriptors:
- urn:alm:descriptor:io.kubernetes:ConfigMap
- description: Use cert-manager to secure in-cluster communication between Cryostat
components. Requires cert-manager to be installed.
displayName: Enable cert-manager Integration
Expand Down
15 changes: 15 additions & 0 deletions bundle/manifests/operator.cryostat.io_cryostats.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ spec:
spec:
description: CryostatSpec defines the desired state of Cryostat
properties:
authProperties:
description: A permission mapping from Cryostat resources to Kubernetes
resources used for authorization.
properties:
configMapName:
description: Name of config map in the local namespace.
type: string
filename:
description: Filename within config map containing the resource
mapping.
type: string
required:
- configMapName
- filename
type: object
enableCertManager:
description: Use cert-manager to secure in-cluster communication between
Cryostat components. Requires cert-manager to be installed.
Expand Down
15 changes: 15 additions & 0 deletions config/crd/bases/operator.cryostat.io_cryostats.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ spec:
spec:
description: CryostatSpec defines the desired state of Cryostat
properties:
authProperties:
description: A permission mapping from Cryostat resources to Kubernetes
resources used for authorization.
properties:
configMapName:
description: Name of config map in the local namespace.
type: string
filename:
description: Filename within config map containing the resource
mapping.
type: string
required:
- configMapName
- filename
type: object
enableCertManager:
description: Use cert-manager to secure in-cluster communication between
Cryostat components. Requires cert-manager to be installed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ spec:
name: ""
version: v1
specDescriptors:
- description: A permission mapping from Cryostat resources to Kubernetes resources
used for authorization.
displayName: Auth Properties
path: authProperties
- description: Name of config map in the local namespace.
displayName: Config Map Name
path: authProperties.configMapName
x-descriptors:
- urn:alm:descriptor:io.kubernetes:ConfigMap
- description: Use cert-manager to secure in-cluster communication between Cryostat
components. Requires cert-manager to be installed.
displayName: Enable cert-manager Integration
Expand Down
34 changes: 34 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,37 @@ spec:
targetCacheSize: -1
targetCacheTTL: 10
```


### Authorization Properties

When running on Openshift, the user is required to have sufficient permissions to certain resources that
are mapped into Cryostat-managed resources for authorization.
Comment thread
tthvo marked this conversation as resolved.
Outdated

The mappings can be specified using a ConfigMap that is compatible with [`OpenShiftAuthManager.properties`](https://github.com/cryostatio/cryostat/blob/main/src/main/resources/io/cryostat/net/openshift/OpenShiftAuthManager.properties). For example:
Comment thread
ebaron marked this conversation as resolved.
Outdated
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: auth-properties
data:
auth.properties: |
TARGET=pods,deployments.apps
RECORDING=pods,pods/exec
CERTIFICATE=deployments.apps,pods,cryostats.operator.cryostat.io
CREDENTIALS=cryostats.operator.cryostat.io
```

The property `.spec.authProperties` can then be set to this ConfigMap to configure Cryostat to use this mapping instead of the default ones.
```yaml
apiVersion: operator.cryostat.io/v1beta1
kind: Cryostat
metadata:
name: cryostat-sample
spec:
authProperties:
configMapName: auth-properties
filename: auth.properties
```

Each `configMapName` must refer to the name of a Config Map in the same namespace as Cryostat. The corresponding `filename` must be a key within that Config Map containting resource mappings.
Comment thread
tthvo marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,28 @@ func NewPodForCR(cr *operatorv1beta1.Cryostat, specs *ServiceSpecs, imageTags *I
volumes = append(volumes, eventTemplateVolume)
}

// Add Auth properties as a volume if specified
if cr.Spec.AuthProperties != (operatorv1beta1.AuthPropertiesConfigMap{}) {
Comment thread
tthvo marked this conversation as resolved.
Outdated
authResourceVolume := corev1.Volume{
Name: "auth-properties-" + cr.Spec.AuthProperties.ConfigMapName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: cr.Spec.AuthProperties.ConfigMapName,
},
Items: []corev1.KeyToPath{
{
Key: cr.Spec.AuthProperties.Filename,
Path: "OpenShiftAuthManager.properties",
Mode: &readOnlyMode,
},
},
},
},
}
volumes = append(volumes, authResourceVolume)
}

// Ensure PV mounts are writable
sc := &corev1.PodSecurityContext{
FSGroup: &fsGroup,
Expand Down Expand Up @@ -498,6 +520,7 @@ func NewCoreContainer(cr *operatorv1beta1.Cryostat, specs *ServiceSpecs, imageTa
templatesPath := "/opt/cryostat.d/templates.d"
clientlibPath := "/opt/cryostat.d/clientlib.d"
probesPath := "/opt/cryostat.d/probes.d"
authPropertiesPath := "/app/resources/io/cryostat/net/openshift/OpenShiftAuthManager.properties"
envs := []corev1.EnvVar{
{
Name: "CRYOSTAT_WEB_PORT",
Expand Down Expand Up @@ -669,6 +692,16 @@ func NewCoreContainer(cr *operatorv1beta1.Cryostat, specs *ServiceSpecs, imageTa
},
}

// Mount Auth properties if specified
if cr.Spec.AuthProperties != (operatorv1beta1.AuthPropertiesConfigMap{}) {
mounts = append(mounts, corev1.VolumeMount{
Name: "auth-properties-" + cr.Spec.AuthProperties.ConfigMapName,
MountPath: authPropertiesPath,
SubPath: "OpenShiftAuthManager.properties",
ReadOnly: true,
})
}

if !cr.Spec.Minimal {
grafanaVars := []corev1.EnvVar{
{
Expand Down
36 changes: 36 additions & 0 deletions internal/controllers/cryostat_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,17 @@ var _ = Describe("CryostatController", func() {
})
})
})
Context("Cryostat CR has OAuth properties", func() {
BeforeEach(func() {
t.objs = append(t.objs, test.NewCryostatWithAuthProperties(), test.NewAuthPropertiesConfigMap())
})
JustBeforeEach(func() {
t.reconcileCryostatFully()
})
It("Should add volumes and volumeMounts to deployment", func() {
t.checkDeploymentHasOAuthProperties()
})
})
})
Describe("reconciling a request in Kubernetes", func() {
JustBeforeEach(func() {
Expand Down Expand Up @@ -1418,6 +1429,17 @@ var _ = Describe("CryostatController", func() {
Expect(kerrors.IsNotFound(err)).To(BeTrue())
})
})
Context("Cryostat CR has OAuth properties", func() {
BeforeEach(func() {
t.objs = append(t.objs, test.NewCryostatWithAuthProperties(), test.NewAuthPropertiesConfigMap())
})
JustBeforeEach(func() {
t.reconcileCryostatFully()
})
It("Should add volumes and volumeMounts to deployment", func() {
t.checkDeploymentHasOAuthProperties()
})
})
Comment thread
tthvo marked this conversation as resolved.
})
})

Expand Down Expand Up @@ -2053,6 +2075,20 @@ func (t *cryostatTestInput) checkDeploymentHasTemplates() {
Expect(volumeMounts).To(Equal(expectedVolumeMounts))
}

func (t *cryostatTestInput) checkDeploymentHasOAuthProperties() {
deployment := &appsv1.Deployment{}
err := t.Client.Get(context.Background(), types.NamespacedName{Name: "cryostat", Namespace: "default"}, deployment)
Expect(err).ToNot(HaveOccurred())

volumes := deployment.Spec.Template.Spec.Volumes
expectedVolumes := test.NewVolumeWithAuthProperties(t.TLS)
Expect(volumes).To(ConsistOf(expectedVolumes))

volumeMounts := deployment.Spec.Template.Spec.Containers[0].VolumeMounts
expectedVolumeMounts := test.NewVolumeMountsWithAuthProperties(t.TLS)
Expect(volumeMounts).To(ConsistOf(expectedVolumeMounts))
Comment thread
tthvo marked this conversation as resolved.
}

func checkCoreContainer(container *corev1.Container, minimal bool, tls bool, externalTLS bool,
tag *string, openshift bool, reportsUrl string, resources corev1.ResourceRequirements) {
Expect(container.Name).To(Equal("cryostat"))
Expand Down
54 changes: 54 additions & 0 deletions internal/test/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,15 @@ func NewCryostatWithResources() *operatorv1beta1.Cryostat {
return cr
}

func NewCryostatWithAuthProperties() *operatorv1beta1.Cryostat {
cr := NewCryostat()
cr.Spec.AuthProperties = operatorv1beta1.AuthPropertiesConfigMap{
ConfigMapName: "authConfigMapName",
Filename: "auth.properties",
}
return cr
}

func newPVCSpec(storageClass string, storageRequest string,
accessModes ...corev1.PersistentVolumeAccessMode) *corev1.PersistentVolumeClaimSpec {
return &corev1.PersistentVolumeClaimSpec{
Expand Down Expand Up @@ -1576,6 +1585,16 @@ func NewVolumeMountsWithTemplates(tls bool) []corev1.VolumeMount {
})
}

func NewVolumeMountsWithAuthProperties(tls bool) []corev1.VolumeMount {
return append(NewCoreVolumeMounts(tls),
corev1.VolumeMount{
Name: "auth-properties-authConfigMapName",
ReadOnly: true,
MountPath: "/app/resources/io/cryostat/net/openshift/OpenShiftAuthManager.properties",
SubPath: "OpenShiftAuthManager.properties",
})
}

func NewCoreLivenessProbe(tls bool) *corev1.Probe {
return &corev1.Probe{
ProbeHandler: newCoreProbeHandler(tls),
Expand Down Expand Up @@ -1781,6 +1800,29 @@ func NewVolumesWithTemplates(tls bool) []corev1.Volume {
})
}

func NewVolumeWithAuthProperties(tls bool) []corev1.Volume {
readOnlyMode := int32(0440)
return append(NewVolumes(false, tls),
corev1.Volume{
Name: "auth-properties-authConfigMapName",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "authConfigMapName",
},
Items: []corev1.KeyToPath{
{
Key: "auth.properties",
Path: "OpenShiftAuthManager.properties",
Mode: &readOnlyMode,
},
},
},
},
},
)
}

func newVolumes(minimal bool, tls bool, certProjections []corev1.VolumeProjection) []corev1.Volume {
readOnlymode := int32(0440)
volumes := []corev1.Volume{
Expand Down Expand Up @@ -2254,6 +2296,18 @@ func NewOtherTemplateConfigMap() *corev1.ConfigMap {
}
}

func NewAuthPropertiesConfigMap() *corev1.ConfigMap {
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "authConfigMapName",
Namespace: "default",
},
Data: map[string]string{
"auth.properties": "CRYOSTAT_RESOURCE=K8S_RESOURCE\nANOTHER_CRYOSTAT_RESOURCE=ANOTHER_K8S_RESOURCE",
},
}
}

func NewNamespace() *corev1.Namespace {
return &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Expand Down