Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.

- Bump `stackable-operator` to 0.87.0 and `stackable-versioned` to 0.6.0 ([#696]).
- Default to OCI for image metadata and product image selection ([#671]).
- Active Directory backend for user-info-fetcher now uses the `service={opacluster}` scope rather than `pod,node` ([#698]).

[#666]: https://github.com/stackabletech/opa-operator/pull/666
[#671]: https://github.com/stackabletech/opa-operator/pull/671
Expand All @@ -27,6 +28,7 @@ All notable changes to this project will be documented in this file.
[#687]: https://github.com/stackabletech/opa-operator/pull/687
[#693]: https://github.com/stackabletech/opa-operator/pull/693
[#696]: https://github.com/stackabletech/opa-operator/pull/696
[#698]: https://github.com/stackabletech/opa-operator/pull/698

## [24.11.1] - 2025-01-10

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

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

6 changes: 3 additions & 3 deletions Cargo.nix

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

9 changes: 9 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ ignore = [
#
# TODO: Remove after https://github.com/kube-rs/kube/pull/1652 is merged
"RUSTSEC-2024-0384",

# https://rustsec.org/advisories/RUSTSEC-2025-0012
# "backoff" is unmainted.
#
# Upstream (kube) has switched to backon in 0.99.0, and an upgrade is scheduled on our end. In the meantime,
# this is a very low-severity problem.
#
# TODO: Remove after upgrading to kube 0.99.
"RUSTSEC-2025-0012",
]

[bans]
Expand Down
7 changes: 4 additions & 3 deletions rust/operator-binary/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ fn build_server_rolegroup_daemonset(
user_info_fetcher_image: &str,
service_account: &ServiceAccount,
) -> Result<DaemonSet> {
let opa_name = opa.metadata.name.as_deref().context(NoNameSnafu)?;
let role = opa.role(opa_role);
let role_group = opa
.rolegroup(rolegroup_ref)
Expand Down Expand Up @@ -979,9 +980,9 @@ fn build_server_rolegroup_daemonset(
SecretClassVolume::new(
ad.kerberos_secret_class_name.clone(),
Some(SecretClassVolumeScope {
pod: true,
node: true,
services: Vec::new(),
pod: false,
node: false,
services: vec![opa_name.to_string()],
listener_volumes: Vec::new(),
}),
)
Expand Down
11 changes: 11 additions & 0 deletions tests/templates/kuttl/ad-user-info/00-limit-range.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
apiVersion: v1
kind: LimitRange
metadata:
name: limit-request-ratio
spec:
limits:
- type: "Container"
maxLimitRequestRatio:
cpu: 5
memory: 1
9 changes: 9 additions & 0 deletions tests/templates/kuttl/ad-user-info/00-patch-ns.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% if test_scenario['values']['openshift'] == 'true' %}
# see https://github.com/stackabletech/issues/issues/566
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: kubectl patch namespace $NAMESPACE -p '{"metadata":{"labels":{"pod-security.kubernetes.io/enforce":"privileged"}}}'
timeout: 120
{% endif %}
10 changes: 10 additions & 0 deletions tests/templates/kuttl/ad-user-info/01-assert.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
{% if lookup('env', 'VECTOR_AGGREGATOR') %}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: vector-aggregator-discovery
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% if lookup('env', 'VECTOR_AGGREGATOR') %}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: vector-aggregator-discovery
data:
ADDRESS: {{ lookup('env', 'VECTOR_AGGREGATOR') }}
{% endif %}
8 changes: 8 additions & 0 deletions tests/templates/kuttl/ad-user-info/10-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
metadata:
name: install-opa
timeout: 300
commands:
- script: kubectl -n $NAMESPACE wait --for=condition=available opaclusters.opa.stackable.tech/test-opa --timeout 301s
60 changes: 60 additions & 0 deletions tests/templates/kuttl/ad-user-info/10-install-opa.yaml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: |
kubectl apply -n $NAMESPACE -f - <<EOF
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test
labels:
opa.stackable.tech/bundle: "true"
data:
test.rego: |
package test

import data.stackable.opa.userinfo.v1 as userinfo

currentUserInfoByUsername := userinfo.userInfoByUsername(input.username)
currentUserInfoById := userinfo.userInfoById(input.id)
---
apiVersion: opa.stackable.tech/v1alpha1
kind: OpaCluster
metadata:
name: test-opa
spec:
image:
{% if test_scenario['values']['opa-latest'].find(",") > 0 %}
custom: "{{ test_scenario['values']['opa-latest'].split(',')[1] }}"
productVersion: "{{ test_scenario['values']['opa-latest'].split(',')[0] }}"
{% else %}
productVersion: "{{ test_scenario['values']['opa-latest'] }}"
{% endif %}
pullPolicy: IfNotPresent
clusterConfig:
userInfo:
backend:
experimentalActiveDirectory:
ldapServer: sble-addc.sble.test
baseDistinguishedName: DC=sble,DC=test
customAttributeMappings:
country: c
kerberosSecretClassName: kerberos-ad
tls:
verification:
server:
caCert:
secretClass: tls-ad
cache: # optional, enabled by default
entryTimeToLive: 60s # optional, defaults to 60s
{% if lookup('env', 'VECTOR_AGGREGATOR') %}
vectorAggregatorConfigMapName: vector-aggregator-discovery
{% endif %}
servers:
config:
logging:
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
roleGroups:
default: {}
14 changes: 14 additions & 0 deletions tests/templates/kuttl/ad-user-info/20-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
metadata:
name: test-regorule
timeout: 300
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: test-regorule
status:
readyReplicas: 1
replicas: 1
29 changes: 29 additions & 0 deletions tests/templates/kuttl/ad-user-info/20-install-test-regorule.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: test-regorule
labels:
app: test-regorule
spec:
replicas: 1
selector:
matchLabels:
app: test-regorule
template:
metadata:
labels:
app: test-regorule
spec:
containers:
- name: test-regorule
image: docker.stackable.tech/stackable/testing-tools:0.2.0-stackable0.0.0-dev
stdin: true
tty: true
resources:
requests:
memory: "128Mi"
cpu: "512m"
limits:
memory: "128Mi"
cpu: "1"
7 changes: 7 additions & 0 deletions tests/templates/kuttl/ad-user-info/30-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestAssert
metadata:
name: test-regorule
commands:
- script: kubectl exec -n $NAMESPACE test-regorule-0 -- python /tmp/test-regorule.py -u 'http://test-opa-server-default:8081/v1/data/test'
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- script: kubectl cp -n $NAMESPACE ./test-regorule.py test-regorule-0:/tmp
75 changes: 75 additions & 0 deletions tests/templates/kuttl/ad-user-info/test-regorule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python
import requests
import argparse
import json

# todo: make the test more comprehensive to check customAttributes
users_and_groups = {
"[email protected]": ["CN=Superset Admins,CN=Users,DC=sble,DC=test", "CN=Domain Users,CN=Users,DC=sble,DC=test", "CN=Users,CN=Builtin,DC=sble,DC=test"],
"[email protected]": ["CN=Domain Users,CN=Users,DC=sble,DC=test", "CN=Users,CN=Builtin,DC=sble,DC=test"],
}


def assertions(
username, response, opa_attribute, expected_groups, expected_attributes={}
):
assert "result" in response
result = response["result"]
print(result)
assert opa_attribute in result, f"expected {opa_attribute} in {result}"

# repeated the right hand side for better output on error
assert "customAttributes" in result[opa_attribute]
assert "groups" in result[opa_attribute]
assert "id" in result[opa_attribute]
assert "username" in result[opa_attribute]

# todo: split out group assertions
print(f"Testing for {username} in groups {expected_groups}")
groups = sorted(result[opa_attribute]["groups"])
expected_groups = sorted(expected_groups)
assert groups == expected_groups, f"got {groups}, expected: {expected_groups}"

# todo: split out customAttribute assertions
print(f"Testing for {username} with customAttributes {expected_attributes}")
custom_attributes = result[opa_attribute]["customAttributes"]
assert (
custom_attributes == expected_attributes
), f"got {custom_attributes}, expected: {expected_attributes}"


if __name__ == "__main__":
all_args = argparse.ArgumentParser()
all_args.add_argument("-u", "--url", required=True, help="OPA service url")
args = vars(all_args.parse_args())
params = {"strict-builtin-errors": "true"}

def make_request(payload):
response = requests.post(args["url"], data=json.dumps(payload), params=params)
expected_status_code = 200
assert (
response.status_code == expected_status_code
), f"got {response.status_code}, expected: {expected_status_code}"
return response.json()

for username, groups in users_and_groups.items():
try:
# todo: try this out locally until it works
# url = 'http://test-opa-svc:8081/v1/data'
payload = {"input": {"username": username}}
response = make_request(payload)
assertions(username, response, "currentUserInfoByUsername", groups, {})

# do the reverse lookup
user_id = response["result"]["currentUserInfoByUsername"]["id"]
payload = {"input": {"id": user_id}}
response = make_request(payload)
assertions(username, response, "currentUserInfoById", groups, {})
except Exception as e:
print(f"exception: {e}")
if response is not None:
print(f"request body: {payload}")
print(f"response body: {response}")
raise e

print("Test successful!")
6 changes: 6 additions & 0 deletions tests/test-definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ tests:
- opa-latest
- keycloak
- openshift
# AD must be initialized (by running ad-init) first,
# and the correct users and groups must be set up (see test-regorule.py)
# name: ad-user-info
# dimensions:
# - opa-latest
# - openshift
- name: aas-user-info
dimensions:
- opa-latest
Expand Down
Loading