Skip to content

Commit

Permalink
Merge branch 'main' into reduce-nightly-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
mjnagel authored Dec 17, 2024
2 parents c6349ba + d701067 commit 485819b
Show file tree
Hide file tree
Showing 31 changed files with 291 additions and 15 deletions.
6 changes: 4 additions & 2 deletions docs/reference/UDS Core/dns.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ title: DNS Configuration
UDS Core deploys two Gateways by default - a Tenant Gateway for end-user applications and an Admin Gateway for administrative applications. You can read more about Istio configuration in UDS Core [here](https://uds.defenseunicorns.com/reference/configuration/ingress/). This section covers how to configure DNS for these Gateways.

### Domain Configuration
Each Gateway is associated to a wildcard DNS entry that is derived from the `DOMAIN` [variable](https://github.com/defenseunicorns/uds-core/blob/e624d73f79bd6739b6808fbdbf5ca75ebb7c1d3c/src/istio/zarf.yaml#L8) in the UDS Core Istio package. When deploying UDS Core, you can expect two Gateways to be created that match the following domain names:

Each Gateway requires a wildcard DNS entry corresponding with the chosen `DOMAIN` and `ADMIN_DOMAIN` [variables](https://github.com/defenseunicorns/uds-core/blob/f6b0b59060a14febd11b0cdc7480f853a57f8520/src/istio/zarf.yaml#L10-L16) (or `admin.<DOMAIN>` if not specifying a separate admin domain). When deploying UDS Core, you can expect two Gateways to be created that match the following domain names:
- `*.<DOMAIN>` / Tenant Gateway
- `*.admin.<DOMAIN>` / Admin Gateway
- `*.<ADMIN_DOMAIN>` / Admin Gateway if setting `ADMIN_DOMAIN`
- `*.admin.<DOMAIN>` / Admin Gateway if NOT setting `ADMIN_DOMAIN`

:::note
The default value for `DOMAIN` is `uds.dev`, which is intended for development purposes only. For non-development purposes, you should override this value by specifying a value for `domain` in your `uds-config.yaml`. You can find instructions on how to do so [here](https://uds.defenseunicorns.com/reference/configuration/ingress/#configure-domain-name-and-tls-for-istio-gateways).
Expand Down
5 changes: 3 additions & 2 deletions docs/reference/configuration/ingress.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ packages:
### Configure Domain Name and TLS for Istio Gateways
By default, the UDS Core Istio Gateways are set up to use the `uds.dev` domain and have a valid TLS certificate packaged. You will want to change the domain name for your environment and provide a valid TLS certificate for this domain.
By default, the UDS Core Istio Gateways are set up to use the `uds.dev` (tenant/passthrough) and `admin.uds.dev` (admin) domains with valid TLS certificates. You will need to change the domain name for your environment and provide a valid TLS certificate for your domain(s).

You can set the TLS certs via overrides in a [UDS Bundle](https://uds.defenseunicorns.com/structure/bundles/) (see below). UDS Core Istio Gateways default to only supporting TLS v1.3, but this can also be overridden per gateway if clients use TLS 1.2 (as seen in the tenant gateway example `value` below).

Expand Down Expand Up @@ -81,11 +81,12 @@ You can then either use environment variables (`UDS_ADMIN_TLS_CERT`, `UDS_ADMIN_
The `TLS_CERT` configuration values must include your specific domain certificate (e.g., `*.uds.dev`) **and** the full certificate chain leading up to a trusted root Certificate Authority (CA), concatenated together. Failing to include the full chain can result in unexpected behavior with certain applications, as some container images may not inherently trust intermediate certificates.
:::

Domain should be set via your [uds-config](https://uds.defenseunicorns.com/reference/cli/quickstart-and-usage/#variables-and-configuration) file using the shared key to override the Zarf Domain Variable (see example `uds-config.yaml` below).
Domain should be set via your [uds-config](https://uds.defenseunicorns.com/reference/cli/quickstart-and-usage/#variables-and-configuration) file using the shared key to override the Zarf Domain Variable (see example `uds-config.yaml` below). By default the `admin_domain` will be set to `admin.<DOMAIN>` but can be overridden to host admin services on a different domain.

```yaml
shared:
domain: yourawesomedomain.com # shared across all packages in a bundle
admin_domain: youradmindomain.com # optional, defaults to admin.yourawesomedomain.com
# TLS Certs/Keys if not provided via environment variables
variables:
Expand Down
31 changes: 31 additions & 0 deletions docs/reference/configuration/uds-optional-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: Optional Features
---

UDS Core adds features to support specific needs that we commonly see across deployments and/or to meet the constraints and controls required by environments. This document contains features we have identified that are conditionally required or requested in environments that are present in core, but must be opted-into to use.

## Classification Banner (_EXPERIMENTAL_)

UDS Core includes a configurable [EnvoyFilter](https://istio.io/latest/docs/reference/config/networking/envoy-filter/) that will add/inject classification banners into user interfaces exposed via the Istio gateways. This is fully configurable to any classification level and can be applied to a set of hosts that you specify. The classification level set via values will also determine the color of the banner background and text, corresponding with the [standard colors](https://www.astrouxds.com/components/classification-markings) required for these markings.

Due to the wide variety of ways that user interfaces can be architected, this approach may not work for all applications and should be validated in a development or staging environment before adoption. For custom built applications, native handling of the banner within the application is often a better path. You can configure the classification banner with bundle overrides, such as the example below:

```yaml
packages:
- name: uds-core
repository: ghcr.io/defenseunicorns/packages/uds/core
ref: x.x.x
overrides:
istio-controlplane:
uds-global-istio-config:
values:
- path: classificationBanner.text
value: "UNCLASSIFIED" # Possible values: UNCLASSIFIED, CUI, CONFIDENTIAL, SECRET, TOP SECRET, TOP SECRET//SCI, UNKNOWN
- path: classificationBanner.addFooter
value: true
- path: classificationBanner.enabledHosts # Opt-in for specific hosts
value:
- keycloak.admin.{{ .Values.domain }} # Note the support for helm templating
- sso.{{ .Values.domain }}
- grafana.admin.uds.dev
```
2 changes: 1 addition & 1 deletion docs/reference/deployment/flavors.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Demo and dev bundles (`k3d-core-demo` and `k3d-core-slim-dev`) are only publishe
| --------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `registry1` | `ghcr.io/defenseunicorns/packages/uds` | [Ironbank](https://p1.dso.mil/services/iron-bank) - DoD hardened images (only supports amd64 architecture currently) |
| `upstream` | `ghcr.io/defenseunicorns/packages/uds` | Various sources, typically DockerHub/GHCR/Quay, these are the default images used by helm charts |
| **ALPHA** `unicorn` | `ghcr.io/defenseunicorns/packages/private/uds` | Industry best images designed with security and minimalism in mind |
| `unicorn` | `ghcr.io/defenseunicorns/packages/private/uds` | Industry best images designed with security and minimalism in mind |

:::note
The `unicorn` flavored packages are only available in a private repository. These packages are available for all members of the Defense Unicorns organization/company, if you are outside the organization [contact us](https://www.defenseunicorns.com/contactus) if you are interested in using this flavor for your mission.
Expand Down
4 changes: 4 additions & 0 deletions src/grafana/chart/templates/uds-package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ spec:
- name: Grafana Dashboard
clientId: uds-core-admin-grafana
redirectUris:
{{- if .Values.adminDomain }}
- "https://grafana.{{ .Values.adminDomain }}/login/generic_oauth"
{{- else }}
- "https://grafana.admin.{{ .Values.domain }}/login/generic_oauth"
{{- end }}

monitor:
- selector:
Expand Down
1 change: 1 addition & 0 deletions src/grafana/chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial

domain: "###ZARF_VAR_DOMAIN###"
adminDomain: "###ZARF_VAR_ADMIN_DOMAIN###"

# Stores Grafana's metadata, including dashboards, data sources, organizations, alerts, and other configurations. Required for HA mode.
postgresql:
Expand Down
2 changes: 2 additions & 0 deletions src/grafana/common/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ components:
namespace: grafana
version: 0.1.0
localPath: ../chart
valuesFiles:
- ../chart/values.yaml
- name: grafana
url: https://grafana.github.io/helm-charts/
version: 8.7.0
Expand Down
2 changes: 1 addition & 1 deletion src/grafana/values/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extraSecretMounts:

grafana.ini:
server:
root_url: https://grafana.admin.###ZARF_VAR_DOMAIN###
root_url: https://grafana.{{ "###ZARF_VAR_ADMIN_DOMAIN###" | default "admin.###ZARF_VAR_DOMAIN###" }}
# Disable telemetry that doesn't function in the airgap
analytics:
reporting_enabled: false
Expand Down
3 changes: 3 additions & 0 deletions src/grafana/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ variables:
description: "Cluster domain"
default: "uds.dev"

- name: ADMIN_DOMAIN
description: "Domain for admin services, defaults to `admin.DOMAIN`"

components:
- name: grafana
required: true
Expand Down
2 changes: 1 addition & 1 deletion src/istio/chart/templates/gateway.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright 2024 Defense Unicorns
# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial

{{- $domain := .Values.domain }}
{{- $domain := tpl .Values.domain . }}
{{- if .Values.tls }}
apiVersion: networking.istio.io/v1beta1
kind: Gateway
Expand Down
161 changes: 161 additions & 0 deletions src/istio/common/chart/templates/classification-banner.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Copyright 2024 Defense Unicorns
# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial

{{- if .Values.classificationBanner.enabledHosts }}
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: classification-banner
namespace: istio-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.compressor
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
response_direction_config:
common_config:
min_content_length: 100
content_type:
- text/html
disable_on_etag_header: true
request_direction_config:
common_config:
enabled:
default_value: false
runtime_key: request_compressor_enabled
compressor_library:
name: text_optimized
typed_config:
"@type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
memory_level: 3
window_bits: 10
compression_level: BEST_COMPRESSION
compression_strategy: DEFAULT_STRATEGY
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value: # Lua script configuration
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |-
-- Setup colors, text and banner div(s)
local classColorMap = {
UNCLASSIFIED = { backgroundColor = "#007a33", textColor = "#ffffff" },
CUI = { backgroundColor = "#502b85", textColor = "#ffffff" },
CONFIDENTIAL = { backgroundColor = "#0033a0", textColor = "#ffffff" },
SECRET = { backgroundColor = "#c8102e", textColor = "#ffffff" },
["TOP SECRET"] = { backgroundColor = "#ff8c00", textColor = "#000000" },
["TOP SECRET//SCI"] = { backgroundColor = "#fce83a", textColor = "#000000" },
UNKNOWN = { backgroundColor = "#000000", textColor = "#ffffff" },
}
local classification = "{{ .Values.classificationBanner.text }}"
local colors = classColorMap[classification] or classColorMap["UNKNOWN"]
local backgroundColor = colors.backgroundColor
local textColor = colors.textColor
local style = "background-color: " .. backgroundColor .. "; color: " .. textColor .. "; height: 24px; line-height: 24px; border: 1px solid transparent; border-radius: 0; position: fixed; left: 0; width: 100vw; text-align: center; margin: 0; z-index: 10000;"
local header = "<div id=\"classification-banner-top\" style=\"" .. style .. " top: 0;\">" .. classification .. "</div>"
local footer = "<div id=\"classification-banner-bottom\" style=\"" .. style .. " bottom: 0;\">" .. classification .. "</div>"
-- Add script to manage padding around the body of the response
local bodyPaddingScript = [[
<script>
window.addEventListener('DOMContentLoaded', function () {
var headerBanner = document.getElementById('classification-banner-top');
var footerBanner = document.getElementById('classification-banner-bottom');
if (headerBanner) {
document.body.style.paddingTop = '24px';
}
if (footerBanner) {
var footerHeight = '24px';
document.body.style.paddingBottom = footerHeight;
var existingFooter = document.querySelector('footer');
if (existingFooter) {
existingFooter.style.marginBottom = footerHeight;
}
}
});
</script>
]]
-- List of enabled hosts as a table for quick lookup, injected via Helm
local enabled_hosts = {
{{- range .Values.classificationBanner.enabledHosts }}
["{{ tpl . $ }}"] = true,
{{- end }}
}
-- Handle request: Extract `:authority` and store it as metadata
function envoy_on_request(request_handle)
local host = request_handle:headers():get(":authority")
request_handle:streamInfo():dynamicMetadata():set("envoy.lua", "host", tostring(host))
end
-- Inject the banner for any hosts where it is enabled
function envoy_on_response(response_handle)
local content_type = response_handle:headers():get("Content-Type") or ""
local host = response_handle:streamInfo():dynamicMetadata():get("envoy.lua")["host"]
if string.find(content_type, "text/html") and enabled_hosts[host] then
local body = response_handle:body():getBytes(0, response_handle:body():length())
local body_text = tostring(body)
-- Insert banners into <body>
{{- if .Values.classificationBanner.addFooter }}
body_text = body_text:gsub("<body([^>]*)>", "<body%1>" .. header .. footer)
{{- else }}
body_text = body_text:gsub("<body([^>]*)>", "<body%1>" .. header)
{{- end }}
-- Insert script into <head>
body_text = body_text:gsub("<head>", "<head>" .. bodyPaddingScript)
response_handle:body():setBytes(body_text)
end
end
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value: # Lua script configuration
name: envoy.filters.http.decompressor
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.decompressor.v3.Decompressor
decompressor_library:
name: small
typed_config:
"@type": "type.googleapis.com/envoy.extensions.compression.gzip.decompressor.v3.Gzip"
chunk_size: 65536
request_direction_config:
common_config:
enabled:
default_value: false
runtime_key: request_decompressor_enabled
{{- end }}
20 changes: 20 additions & 0 deletions src/istio/common/chart/values.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"classificationBanner": {
"type": "object",
"properties": {
"addFooter": {
"type": "boolean",
"description": "Indicates whether to add a footer to the classification banner."
},
"text": {
"type": ["string", "null"],
"pattern": "^(?i)(UNCLASSIFIED|CUI|CONFIDENTIAL|SECRET|TOP SECRET|TOP SECRET//SCI|UNKNOWN|)$",
"description": "The classification banner text must match one of the allowed values (case-insensitive): UNCLASSIFIED, CONTROLLED, CONFIDENTIAL, SECRET, TOP SECRET, TOP SECRET//SCI, UNKNOWN, or it can be an empty string or null."
}
}
}
}
}
13 changes: 13 additions & 0 deletions src/istio/common/chart/values.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
# SPDX-License-Identifier: AGPL-3.0-or-later OR Commercial
classificationBanner:
text: "UNKNOWN"
addFooter: true
# Hosts to enable the banner on
enabledHosts: []
# Examples (supports helm templating)
# - keycloak.{{ .Values.adminDomain }}
# - sso.{{ .Values.domain }}
# - grafana.admin.uds.dev

domain: "###ZARF_VAR_DOMAIN###"
# Note: This does not handle an empty admin domain zarf var
adminDomain: "###ZARF_VAR_ADMIN_DOMAIN###"
2 changes: 2 additions & 0 deletions src/istio/common/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ components:
namespace: istio-system
version: 0.1.0
localPath: chart
valuesFiles:
- "chart/values.yaml"
actions:
onDeploy:
before:
Expand Down
3 changes: 2 additions & 1 deletion src/istio/values/config-admin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial

name: admin
domain: "admin.###ZARF_VAR_DOMAIN###"
# Accommodate a specific admin domain or the default of `admin.DOMAIN`
domain: '{{ "###ZARF_VAR_ADMIN_DOMAIN###" | default "admin.###ZARF_VAR_DOMAIN###" }}'
tls:
servers:
keycloak:
Expand Down
3 changes: 3 additions & 0 deletions src/istio/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ variables:
description: "Cluster domain"
default: "uds.dev"

- name: ADMIN_DOMAIN
description: "Domain for admin services, defaults to `admin.DOMAIN`"

components:
- name: istio-controlplane
required: true
Expand Down
2 changes: 2 additions & 0 deletions src/keycloak/chart/templates/statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ spec:
# Common configuration
- name: UDS_DOMAIN
value: "{{ .Values.domain }}"
- name: UDS_ADMIN_DOMAIN
value: "{{ tpl .Values.adminDomain . }}"

# Enable health and metrics endpoints
- name: KC_HEALTH_ENABLED
Expand Down
3 changes: 3 additions & 0 deletions src/keycloak/chart/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
"domain": {
"type": "string"
},
"adminDomain": {
"type": "string"
},
"enableServiceLinks": {
"type": "boolean"
},
Expand Down
2 changes: 2 additions & 0 deletions src/keycloak/chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ configImage: ghcr.io/defenseunicorns/uds/identity-config:0.8.0

# The public domain name of the Keycloak server
domain: "###ZARF_VAR_DOMAIN###"
# The admin domain for hosts to trust clients on
adminDomain: '{{ "###ZARF_VAR_ADMIN_DOMAIN###" | default "admin.###ZARF_VAR_DOMAIN###" }}'

# Additional Istio Gateways that expose Keycloak, to allow for client cert usage
# A prefix of `istio-` is required for namespaces to prevent accidental misconfiguration
Expand Down
2 changes: 2 additions & 0 deletions src/keycloak/common/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ components:
# renovate: datasource=docker depName=quay.io/keycloak/keycloak versioning=semver
version: 26.0.7
localPath: ../chart
valuesFiles:
- ../chart/values.yaml
actions:
onDeploy:
before:
Expand Down
Loading

0 comments on commit 485819b

Please sign in to comment.