Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ uds-docs/**
**.backup
**/.playwright/**
**/.playwright

coverage/**
Comment thread
mjnagel marked this conversation as resolved.
2 changes: 2 additions & 0 deletions bundles/k3d-slim-dev/uds-bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ packages:
# x-release-please-start-version
ref: 0.38.0
# x-release-please-end
optionalComponents:
- istio-ambient
Comment thread
mjnagel marked this conversation as resolved.
Outdated
overrides:
pepr-uds-core:
module:
Expand Down
253 changes: 253 additions & 0 deletions docs/reference/configuration/authorization-policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
---
title: Authorization Policies in Ambient Mode
sidebar:
order: 2
---

## Overview

In an ambient mode service mesh environment, security is enforced using Istio AuthorizationPolicies. The UDS‑Core operator automatically generates these **ALLOW** policies based on your UDSPackage configuration. The generated policies ensure that only explicitly permitted traffic is allowed, enforcing per‑port access control for your applications. In addition to handling custom ingress rules (allow/expose), the operator also processes monitor configurations to protect monitoring endpoints (such as Prometheus metrics).
Comment thread
mjnagel marked this conversation as resolved.
Outdated

## Policy Generation Process

Authorization policies are dynamically created from the UDSPackage configuration through the following steps:

1. **Identify Applicable Rules:**
- The operator processes three sections from the UDSPackage:
- **Allow Rules:** Custom network rules defined under `spec.network.allow`.
- **Expose Rules:** Rules defined under `spec.network.expose` for exposing services on an Istio Gateway.
- **Monitor Rules:** Rules defined under `spec.monitor` to secure monitoring endpoints.
- Even if a rule does not specify any port, a policy is generated—resulting in a rule with only a `from` clause that applies namespace-wide.

2. **Process Allow Rules:**
- Each rule in `spec.network.allow` is evaluated to determine its target ports (if provided) and remote source attributes:
- If `remoteGenerated` is set to **IntraNamespace**, the source is set to the package’s namespace.
- If a non‑empty, non‑asterisk `remoteNamespace` is provided, that namespace is used as the source.
- If `remoteNamespace` is `"*"` or if `remoteGenerated` is set to **Anywhere**, the source is defined using a negative match (i.e. traffic from any namespace except the package’s namespace).
- If `remoteServiceAccount` is provided, it overrides the namespace-based source by specifying a principal of the form `cluster.local/ns/<namespace>/sa/<serviceAccount>`.

3. **Process Expose Rules:**
- Rules in `spec.network.expose` are processed similarly:
- For expose rules, if `targetPort` is defined it is used; otherwise the rule falls back to using `port`.
- If the gateway is **Admin**, the source is explicitly set to `{ namespaces: ["istio-admin-gateway"] }`; otherwise, the source defaults to the package’s namespace.

4. **Process Monitor Rules:**
- Each monitor entry in `spec.monitor` is processed separately.
- A monitor rule must provide a valid selector (or podSelector) and a targetPort.
- For each monitor, an individual AuthorizationPolicy is created to restrict access (typically from the `monitoring` namespace) to the specified port (e.g. for Prometheus metrics).

5. **Group and Create Policies:**
- **Grouping by Selector:**
Rules that include a pod selector (i.e. a `selector` field) are grouped together using a canonicalization process. This ensures that rules with the same key‑value pairs (regardless of order) are combined into a single workload‑specific policy.
- For each group, a unique workload AuthorizationPolicy is generated. The policy name is derived from the package name and the selector:
- If the selector includes an `"app"` key, its value (with any trailing `-pod` removed) is used.
- Otherwise, if `"app.kubernetes.io/name"` is provided, its value (with `-pod` removed and `-workload` appended) is used.
- If neither key is present, the fallback name is `"workload"`.
- **Namespace‑Wide Policy:**
Rules that do not include a selector are merged into a single namespace‑wide policy.
- **Monitor Policies:**
Each monitor entry produces its own AuthorizationPolicy that protects the designated metrics endpoint.

6. **Policy Structure:**
- Each generated policy uses the **ALLOW** action.
- If port information is provided, the rule includes a `to` clause that specifies the allowed ports.
- If no ports are defined, the rule contains only a `from` clause.
- Metadata labels (including the package name and generation) are added for traceability.

## Example Use Cases

### Example 1: Allow Ingress from a Specific Namespace (No Selector)

**UDSPackage Configuration:**
```yaml
spec:
network:
allow:
- direction: Ingress
remoteNamespace: "external-app"
port: 8080
```

**Generated AuthorizationPolicy:**
```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: protect-my-app-ns
namespace: my-app-namespace
labels:
uds/package: my-app
uds/generation: "1"
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["external-app"]
to:
- operation:
ports: ["8080"]
```

### Example 2: Allow Ingress Only to a Specific Pod Selector

**UDSPackage Configuration:**
```yaml
spec:
network:
allow:
- direction: Ingress
remoteNamespace: "external-app"
selector:
app: "frontend"
port: 8080
```

**Generated AuthorizationPolicy:**
```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: protect-my-app-frontend
namespace: my-app-namespace
labels:
uds/package: my-app
uds/generation: "1"
spec:
action: ALLOW
selector:
matchLabels:
app: "frontend"
rules:
- from:
- source:
namespaces: ["external-app"]
to:
- operation:
ports: ["8080"]
```

### Example 3: Intra-Namespace Rule Without Port
**UDSPackage Configuration (for a package named "loki" in the "loki" namespace):**

```yaml
spec:
network:
allow:
- direction: Ingress
remoteGenerated: IntraNamespace
```

**Generated AuthorizationPolicy:**

```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: protect-loki-ns
namespace: loki
labels:
uds/package: loki
uds/generation: "1"
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["loki"]
```

### Example 4: Merging Multiple Rules with the Same Selector
**UDSPackage Configuration:**

```yaml
spec:
network:
allow:
- direction: Ingress
remoteGenerated: Anywhere
selector:
app: "my-app"
port: 80
- direction: Ingress
remoteGenerated: Anywhere
selector:
app: "my-app"
port: 443
```

**Generated AuthorizationPolicy (for a package named "myapp" in the "my-namespace" namespace):**
```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: protect-myapp-my-app
namespace: my-namespace
labels:
uds/package: my-app
uds/generation: "1"
spec:
action: ALLOW
selector:
matchLabels:
app: "my-app"
rules:
- from:
- source:
notNamespaces: ["my-namespace"]
to:
- operation:
ports: ["80", "443"]
```

### Example 5: Monitor Rule for Securing a Metrics Endpoint
**UDSPackage Configuration:**

```yaml
spec:
monitor:
- description: Metrics
podSelector:
app.kubernetes.io/name: grafana
portName: service
selector:
app.kubernetes.io/name: grafana
targetPort: 3000
```

**Generated AuthorizationPolicy:**
```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: protect-grafana-monitor-grafana-workload
namespace: grafana
labels:
uds/package: grafana
uds/generation: "1"
spec:
action: ALLOW
selector:
matchLabels:
app.kubernetes.io/name: grafana
rules:
- from:
- source:
namespaces: ["monitoring"]
to:
- operation:
ports: ["3000"]
```

## Summary
- The UDS‑Core operator automatically generates ALLOW Istio AuthorizationPolicies based on your UDSPackage configuration.

- Policies are generated for rules defined in the allow, expose, and monitor blocks.

- Rules with pod selectors result in workload‑specific policies, while rules without selectors are merged into a single namespace‑wide policy.

- Each monitor entry produces its own policy, ensuring that monitoring endpoints (e.g. metrics) are secured.

- If port information is provided, policies enforce allowed ports; if not, they only include a from clause.

- Metadata is added for traceability.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ sidebar:
</tr>
</thead>
<tbody>
<tr><td style="white-space: nowrap;">allow</td><td style="white-space: nowrap;"><a href="#Allow">Allow[]</a></td><td>Allow specific traffic (namespace will have a default-deny policy)</td></tr><tr><td style="white-space: nowrap;">expose</td><td style="white-space: nowrap;"><a href="#Expose">Expose[]</a></td><td>Expose a service on an Istio Gateway</td></tr>
<tr><td style="white-space: nowrap;">allow</td><td style="white-space: nowrap;"><a href="#Allow">Allow[]</a></td><td>Allow specific traffic (namespace will have a default-deny policy)</td></tr><tr><td style="white-space: nowrap;">expose</td><td style="white-space: nowrap;"><a href="#Expose">Expose[]</a></td><td>Expose a service on an Istio Gateway</td></tr><tr><td style="white-space: nowrap;">serviceMesh</td><td style="white-space: nowrap;"><a href="#ServiceMesh">ServiceMesh</a></td><td>Service mesh configuration for the package</td></tr>
</tbody>
</table>
</div>
Expand All @@ -126,7 +126,7 @@ sidebar:
</tr>
</thead>
<tbody>
<tr><td style="white-space: nowrap;">description</td><td style="white-space: nowrap;">string</td><td>A description of the policy, this will become part of the policy name</td></tr><tr><td style="white-space: nowrap;">direction</td><td style="white-space: nowrap;">string (enum):<ul><li><code>Ingress</code></li><li><code>Egress</code></li></ul></td><td>The direction of the traffic</td></tr><tr><td style="white-space: nowrap;">labels</td><td style="white-space: nowrap;"></td><td>The labels to apply to the policy</td></tr><tr><td style="white-space: nowrap;">podLabels</td><td style="white-space: nowrap;"></td><td>Deprecated: use selector</td></tr><tr><td style="white-space: nowrap;">port</td><td style="white-space: nowrap;">number</td><td>The port to allow (protocol is always TCP)</td></tr><tr><td style="white-space: nowrap;">ports</td><td style="white-space: nowrap;">number[]</td><td>A list of ports to allow (protocol is always TCP)</td></tr><tr><td style="white-space: nowrap;">remoteCidr</td><td style="white-space: nowrap;">string</td><td>Custom generated policy CIDR</td></tr><tr><td style="white-space: nowrap;">remoteGenerated</td><td style="white-space: nowrap;">string (enum):<ul><li><code>KubeAPI</code></li><li><code>KubeNodes</code></li><li><code>IntraNamespace</code></li><li><code>CloudMetadata</code></li><li><code>Anywhere</code></li></ul></td><td>Custom generated remote selector for the policy</td></tr><tr><td style="white-space: nowrap;">remoteNamespace</td><td style="white-space: nowrap;">string</td><td>The remote namespace to allow traffic to/from. Use * or empty string to allow all namespaces</td></tr><tr><td style="white-space: nowrap;">remotePodLabels</td><td style="white-space: nowrap;"></td><td>Deprecated: use remoteSelector</td></tr><tr><td style="white-space: nowrap;">remoteSelector</td><td style="white-space: nowrap;"></td><td>The remote pod selector labels to allow traffic to/from</td></tr><tr><td style="white-space: nowrap;">selector</td><td style="white-space: nowrap;"></td><td>Labels to match pods in the namespace to apply the policy to. Leave empty to apply to all pods in the namespace</td></tr>
<tr><td style="white-space: nowrap;">description</td><td style="white-space: nowrap;">string</td><td>A description of the policy, this will become part of the policy name</td></tr><tr><td style="white-space: nowrap;">direction</td><td style="white-space: nowrap;">string (enum):<ul><li><code>Ingress</code></li><li><code>Egress</code></li></ul></td><td>The direction of the traffic</td></tr><tr><td style="white-space: nowrap;">labels</td><td style="white-space: nowrap;"></td><td>The labels to apply to the policy</td></tr><tr><td style="white-space: nowrap;">podLabels</td><td style="white-space: nowrap;"></td><td>Deprecated: use selector</td></tr><tr><td style="white-space: nowrap;">port</td><td style="white-space: nowrap;">number</td><td>The port to allow (protocol is always TCP)</td></tr><tr><td style="white-space: nowrap;">ports</td><td style="white-space: nowrap;">number[]</td><td>A list of ports to allow (protocol is always TCP)</td></tr><tr><td style="white-space: nowrap;">remoteCidr</td><td style="white-space: nowrap;">string</td><td>Custom generated policy CIDR</td></tr><tr><td style="white-space: nowrap;">remoteGenerated</td><td style="white-space: nowrap;">string (enum):<ul><li><code>KubeAPI</code></li><li><code>KubeNodes</code></li><li><code>IntraNamespace</code></li><li><code>CloudMetadata</code></li><li><code>Anywhere</code></li></ul></td><td>Custom generated remote selector for the policy</td></tr><tr><td style="white-space: nowrap;">remoteNamespace</td><td style="white-space: nowrap;">string</td><td>The remote namespace to allow traffic to/from. Use * or empty string to allow all namespaces</td></tr><tr><td style="white-space: nowrap;">remotePodLabels</td><td style="white-space: nowrap;"></td><td>Deprecated: use remoteSelector</td></tr><tr><td style="white-space: nowrap;">remoteSelector</td><td style="white-space: nowrap;"></td><td>The remote pod selector labels to allow traffic to/from</td></tr><tr><td style="white-space: nowrap;">remoteServiceAccount</td><td style="white-space: nowrap;">string</td><td>The remote service account to restrict incoming traffic from within the remote namespace. Only valid for Ingress rules.</td></tr><tr><td style="white-space: nowrap;">selector</td><td style="white-space: nowrap;"></td><td>Labels to match pods in the namespace to apply the policy to. Leave empty to apply to all pods in the namespace</td></tr>
</tbody>
</table>
</div>
Expand Down Expand Up @@ -475,6 +475,24 @@ Valid Options: FROM_PROTOCOL_DEFAULT, FROM_REQUEST_PORT</td></tr><tr><td style="
</table>
</div>

<a id="ServiceMesh"></a>
<div style="margin-left: 80px; padding-top: 30px;">

#### ServiceMesh
<table style="width: 100%; table-layout: fixed;">
<thead>
<tr>
<th style="width: 20%; white-space: nowrap;">Field</th>
<th style="width: 25%; white-space: nowrap;">Type</th>
<th style="width: 55%; white-space: nowrap;">Description</th>
</tr>
</thead>
<tbody>
<tr><td style="white-space: nowrap;">ambient</td><td style="white-space: nowrap;">boolean</td><td>Enable ambient authentication for the service mesh</td></tr>
</tbody>
</table>
</div>

<a id="Sso"></a>
<div style="margin-left: 60px; padding-top: 30px;">

Expand Down
24 changes: 24 additions & 0 deletions schemas/package-v1alpha1.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@
"$ref": "#/definitions/Expose"
},
"description": "Expose a service on an Istio Gateway"
},
"serviceMesh": {
"$ref": "#/definitions/ServiceMesh",
"description": "Service mesh configuration for the package"
}
},
"required": [],
Expand Down Expand Up @@ -224,6 +228,10 @@
},
"description": "Labels to match pods in the namespace to apply the policy to. Leave empty to apply to all pods in the namespace\nThe labels to apply to the policy\nDeprecated: use selector\nDeprecated: use remoteSelector\nThe remote pod selector labels to allow traffic to/from\nSpecifies attributes for the client.\nLabels to match pods to automatically protect with authservice. Leave empty to disable authservice protection\nConfiguration options for the mapper.\nA template for the generated secret"
},
"remoteServiceAccount": {
"type": "string",
"description": "The remote service account to restrict incoming traffic from within the remote\nnamespace. Only valid for Ingress rules."
},
"selector": {
"type": "object",
"additionalProperties": {
Expand Down Expand Up @@ -783,6 +791,19 @@
"required": [],
"title": "FluffyURI"
},
"ServiceMesh": {
"type": "object",
"additionalProperties": false,
"properties": {
"ambient": {
"type": "boolean",
"description": "Enable ambient authentication for the service mesh"
}
},
"required": [],
"title": "ServiceMesh",
"description": "Service mesh configuration for the package"
},
"Sso": {
"type": "object",
"additionalProperties": false,
Expand Down Expand Up @@ -958,6 +979,9 @@
"type": "object",
"additionalProperties": false,
"properties": {
"authorizationPolicyCount": {
"type": "integer"
},
"authserviceClients": {
"type": "array",
"items": {
Expand Down
Loading