Skip to content

Standing-Access Scan

Overview

Per-run pipeline credentials remove the pipeline’s standing access, but every namespace still has bindings that persist: built-in service accounts, the broker’s own binding, and anything granted by hand. A Resource Manager scan runs against each namespace resource and reports those subjects as identities and the roles they hold as groups, with privileged roles flagged.

What you’ll accomplish:

  • Grant the broker read-only access for scanning
  • Upload a scan script and enable scanning on the resource type
  • Run a scan and read the inventory

How It Works

A scan runs per resource. The broker receives the resource’s fields upper-cased with a RESOURCE_ prefix (RESOURCE_CLUSTER_NAME, RESOURCE_NAMESPACE) and the path to write results to (BROKER_INJECTED_SCAN_OUTPUT_PATH). No variable mapping is needed. The broker uploads the JSON, and Britive imports it.

Scan payloadContents
data.identitiesEvery subject bound in the namespace: its service accounts, plus users, groups and service accounts from other namespaces named in its RoleBindings
data.groupsOne per Role or ClusterRole bound in the namespace; members are identity ids; privileged for admin, edit, cluster-admin and roles with wildcard verbs
data.permissions, data.permission_mappingEmpty; access is expressed as group membership

Britive’s per-run gha-* service accounts and bindings are excluded: they are short-lived checkouts, not standing access.

A scan reports what is inside existing resources; it does not create resources.

Before You Begin

  • The aro-namespace resource type and resources from Namespace Resource Type
  • Access Broker 3.x with configuration version 2 (BRITIVE_BROKER_CONFIG_VERSION=2), which enables scans
  • jq in the broker image

Steps

Grant the broker read-only scan access

Cluster-wide get and list on service accounts and RBAC objects. No Secrets.

rbac-scan.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: britive-broker-scan
rules:
  - apiGroups: [""]
    resources: ["namespaces", "serviceaccounts"]
    verbs: ["get", "list"]
  - apiGroups: ["rbac.authorization.k8s.io"]
    resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: britive-broker-scan
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: britive-broker-scan
subjects:
  - kind: ServiceAccount
    name: britive-broker
    namespace: britive-system
oc apply -f rbac-scan.yaml

Write the scan script

The script writes lists to files before jq reads them (OpenShift’s ClusterRole list is too large to pass as an argument), builds the payload, and validates it against the import’s rules before writing:

  • every identity has non-empty email, first_name and last_name
  • identity and group id and name are at most 50 characters (longer ids are shortened with a checksum suffix)
  • groups carry type: "User group" and is_active
  • every group member is an identity id
scan.sh (excerpt)
OUT=${BROKER_INJECTED_SCAN_OUTPUT_PATH:?}
CLUSTER=${RESOURCE_CLUSTER_NAME:?}
NS=${RESOURCE_NAMESPACE:?}
KC="/etc/britive/kubeconfigs/${CLUSTER}.kubeconfig"
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT

oc --kubeconfig "$KC" -n "$NS" get serviceaccounts -o json >"$TMP/sas.json"
oc --kubeconfig "$KC" -n "$NS" get rolebindings -o json >"$TMP/rbs.json"
oc --kubeconfig "$KC" -n "$NS" get roles -o json >"$TMP/roles.json"
oc --kubeconfig "$KC" get clusterroles -o json \
  | jq '[.items[] | {key: "ClusterRole/\(.metadata.name)",
                    value: ([.rules[]? | (.verbs // []) | index("*")] | any)}] | from_entries' \
  >"$TMP/cwild.json"

# jq -n --slurpfile ... builds {data: {identities, groups, permissions: [], permission_mapping: []}, metadata}
# identity: {id, name, type: "User", description, created_on, is_active,
#            attributes: {email, first_name, last_name, kind, username, ...}}
# group:    {id, name, type: "User group", description, created_on, is_active, members, attributes}

The full script is kept on the platform, in the configuration of the resource type, where you upload it in the next step.

Enable scanning on the resource type

main.tf
resource "britive_resource_manager_resource_type" "aro_namespace" {
  name         = "aro-namespace"
  scan_enabled = true
  # parameters as before
}

resource "britive_resource_manager_resource_type_scan_settings" "aro_namespace" {
  resource_type_id = britive_resource_manager_resource_type.aro_namespace.id
  template_type    = "FilePath"
  script_file_path = "${path.module}/scripts/scan.sh"
  time_limit       = 5 # minutes
}

The scan resources need the Britive Terraform provider 3.0.3 or later.

Schedule a daily scan

main.tf
resource "britive_resource_manager_resource_type_schedule_scan" "daily" {
  resource_type_id = britive_resource_manager_resource_type.aro_namespace.id
  name             = "aro-namespace-daily"
  frequency_type   = "Daily"
  start_time       = "06:00"

  resource_labels {
    label_key = "britive-managed"
    values    = ["true"]
  }

  depends_on = [britive_resource_manager_resource_type_scan_settings.aro_namespace]
}

Run a scan

In the Britive console, open the aro-namespace resource type and click Scan Resources.

Verify

A clean namespace with only OpenShift defaults and the broker’s binding reports 5 identities and 4 roles, none privileged:

Group (role)Members
ClusterRole/britive-broker-nssa:britive-system/britive-broker
ClusterRole/system:deployersa:deployer
ClusterRole/system:image-buildersa:builder
ClusterRole/system:image-pullergroup:system:serviceaccounts:<namespace>

The broker log shows the scan and the upload:

msg="broker response" response.action=scan response.status=SUCCESS
msg="broker response" response.action=upload response.status=SUCCESS

Grant someone edit in the namespace and scan again: the role appears with privileged=true.

Troubleshoot

SymptomCauseFix
/usr/bin/jq: Argument list too longLarge lists passed with --argjsonWrite lists to files and use --slurpfile
Console: “An unknown error has occurred” while the broker logs upload SUCCESSThe import rejected the payloadCheck required identity fields, 50-character ids and group type; validate before writing
forbidden: ... cannot list resource "clusterroles"Scan role missing or not boundApply britive-broker-scan and its ClusterRoleBinding
Scan request never reaches the brokerScanning not enabled, or config version 1scan_enabled = true; BRITIVE_BROKER_CONFIG_VERSION=2

Next Steps

Last updated on