Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
82 changes: 82 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,82 @@
#!/usr/bin/env python
import requests
import argparse
import json

# todo: make the test more comprehensive to check customAttributes
users_and_groups = {
"alice@sble.test": [
"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",
],
"bob@sble.test": [
"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