Skip to content

Commit c6b02e6

Browse files
committed
Merge branch 'main' of github.com:hopehadfield/rhdh into feature/RHIDP-14879
2 parents 9742e73 + 2c75ce0 commit c6b02e6

27 files changed

Lines changed: 1475 additions & 537 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# ARO disconnected deployment variables.
2+
# Copy this file to .env and edit it. The .env file is ignored by git.
3+
# Used by install-aro-disconnected.sh and create-azure-firewall-rules.sh on the local machine.
4+
5+
BASE_NAME=aro-disconnected
6+
SUFFIX=6
7+
LOCATION=eastus
8+
RESOURCEGROUP=${BASE_NAME}_${SUFFIX}
9+
CLUSTER=${BASE_NAME}_${SUFFIX}
10+
VNET_NAME=${BASE_NAME}-vnet_${SUFFIX}
11+
FIREWALL_NAME=${BASE_NAME}-firewall_${SUFFIX}
12+
FIREWALL_COLLECTION_NAME=azure_ms
13+
FIREWALL_ALLOWED_LIST_BASE="management.azure.com mirror.openshift.com login.microsoftonline.com gcs.prod.monitoring.core.windows.net *.blob.core.windows.net *.servicebus.windows.net *.table.core.windows.net"
14+
FIREWALL_ALLOWED_LIST_INSTALL="*.quay.io sso.redhat.com registry.redhat.io management.azure.com mirror.openshift.com api.openshift.com registry.access.redhat.com"
15+
BASTION_IMAGE=RedHat:RHEL:10_1:latest
16+
SSH_KEY_NAME=azure-disconnected-key_${SUFFIX}
17+
WORKER_COUNT=4
18+
PULL_SECRET_FILE=pull-secret.txt
19+
OPENSHIFT_VERSION=4.19.20
20+
BASTION_NAME=bastion-${SUFFIX}
21+
BASTION_SOURCE_ADDRESS_PREFIX=
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.env
2+
.local/
3+
pull-secret.txt
4+
*_access-information.txt
5+
azure-disconnected-key_*
6+
*.key
7+
*.pem
8+
*.pub
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Manual ARO Disconnected Cluster
2+
3+
These scripts provision an Azure Red Hat OpenShift (ARO) cluster in a disconnected Azure network for
4+
manual RHDH testing. They are not connected to Prow.
5+
6+
The workflow is based on the
7+
[ARO disconnected installation guide](https://github.com/redhat-cop/ocp-disconnected-docs/blob/main/AROInstall.md).
8+
Restricting outbound traffic can violate the ARO support policy; use this workflow only where that
9+
trade-off is understood.
10+
11+
## Prerequisites
12+
13+
- Azure CLI with access to the target subscription
14+
- `ssh-keygen` on the local workstation
15+
- An OpenShift pull secret from <https://console.redhat.com/openshift/install/pull-secret>
16+
- A bastion VM image available in the selected Azure region
17+
18+
## Configuration
19+
20+
Run these commands in this directory:
21+
22+
```bash
23+
cp .env.example .env
24+
```
25+
26+
Edit at least `SUFFIX`, `LOCATION`, `OPENSHIFT_VERSION`, and `BASTION_SOURCE_ADDRESS_PREFIX`. Set
27+
the latter to the public IP address or CIDR of the workstation that will SSH to the bastion, for
28+
example `198.51.100.10/32`. Place `pull-secret.txt` in this directory, or set `PULL_SECRET_FILE` to
29+
an absolute path. The configuration contains names and network allow-lists only; it must not contain
30+
registry passwords, tokens, or other secret values.
31+
32+
## Workflow
33+
34+
### 1. Create the ARO cluster and bastion
35+
36+
Run on the local workstation:
37+
38+
```bash
39+
./install-aro-disconnected.sh
40+
```
41+
42+
This creates the resource group, VNet, master and worker subnets, Azure Firewall, routes, private
43+
ARO cluster, and bastion VM. The bastion allows SSH only from `BASTION_SOURCE_ADDRESS_PREFIX`. The
44+
script creates an SSH key pair and writes the SSH command, API server, console URL, and kubeadmin
45+
credentials to a `*_access-information.txt` file with mode `0600`. The file is ignored by git.
46+
47+
The installer firewall rule is removed after ARO creation. Use the next step to add the outbound
48+
rules needed by the workloads you run.
49+
50+
### 2. Add workload firewall rules
51+
52+
Run on the local workstation:
53+
54+
```bash
55+
./create-azure-firewall-rules.sh
56+
```
57+
58+
The script creates the configured rule collection and adds each rule from its indexed rule list in
59+
order. If the collection already exists, it asks before replacing it.
60+
61+
### 3. Set up the bastion
62+
63+
Copy the setup script to the bastion, then SSH to it using the protected access information file.
64+
Replace the placeholders with the values from that file:
65+
66+
```bash
67+
scp -i <SSH_KEY_PATH> setup-bastion.sh azureuser@<BASTION_PUBLIC_IP>:~/setup-bastion.sh
68+
ssh -i <SSH_KEY_PATH> azureuser@<BASTION_PUBLIC_IP>
69+
```
70+
71+
Export the cluster values in the bastion shell without committing or logging them:
72+
73+
```bash
74+
export API_SERVER='https://...'
75+
export KUBEADMIN_PASSWORD='...'
76+
export OPENSHIFT_VERSION='4.19.20'
77+
chmod 700 ~/setup-bastion.sh
78+
~/setup-bastion.sh
79+
```
80+
81+
The script installs version-pinned `oc`, Helm, and `opm` binaries, verifies their published SHA-256
82+
manifests, installs the pinned `umoci` release after checksum verification, enables the OpenShift
83+
internal registry, and resizes the bastion partitions. The default Helm and umoci versions can be
84+
overridden with `HELM_VERSION` and `UMOCI_VERSION`.
85+
86+
## Cleanup
87+
88+
When testing is finished, delete the resource group from the local workstation:
89+
90+
```bash
91+
az group delete --name "$RESOURCEGROUP" --yes --no-wait
92+
```
93+
94+
The command reads `RESOURCEGROUP` from the `.env` file if it is sourced in the current shell.
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Run on: LOCAL MACHINE (workstation with Azure CLI installed).
4+
# Purpose: Create the application rules required by an ARO disconnected cluster.
5+
# Based on: https://github.com/redhat-cop/ocp-disconnected-docs/blob/main/AROInstall.md
6+
# Requires: An ARO cluster and Azure Firewall created by install-aro-disconnected.sh.
7+
#
8+
9+
set -euo pipefail
10+
11+
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
12+
13+
print_status() {
14+
printf '[INFO] %s\n' "$1"
15+
}
16+
17+
print_warning() {
18+
printf '[WARNING] %s\n' "$1"
19+
}
20+
21+
print_error() {
22+
printf '[ERROR] %s\n' "$1" >&2
23+
}
24+
25+
if [[ ! -f "${SCRIPT_DIR}/.env" ]]; then
26+
print_error 'Missing .env. Copy .env.example to .env and edit it first.'
27+
exit 1
28+
fi
29+
30+
# shellcheck disable=SC1091
31+
source "${SCRIPT_DIR}/.env"
32+
33+
if [[ -z "${RESOURCEGROUP:-}" || -z "${FIREWALL_NAME:-}" || -z "${FIREWALL_COLLECTION_NAME:-}" ]]; then
34+
print_error 'RESOURCEGROUP, FIREWALL_NAME, and FIREWALL_COLLECTION_NAME are required.'
35+
exit 1
36+
fi
37+
38+
RESOURCE_GROUP="$RESOURCEGROUP"
39+
RULE_COLLECTION_NAME="$FIREWALL_COLLECTION_NAME"
40+
SOURCE_ADDRESSES=(10.0.0.0/24 10.0.1.0/24)
41+
PROTOCOLS=(Http=80 Https=443)
42+
RULE_NAMES=(
43+
azure
44+
redhat
45+
ms-graph
46+
github
47+
gitlab
48+
pagerduty
49+
quay
50+
okta
51+
auth0
52+
atlassian
53+
atlassian-third-party
54+
)
55+
RULE_TARGETS=(
56+
'management.azure.com mirror.openshift.com login.microsoftonline.com gcs.prod.monitoring.core.windows.net *.blob.core.windows.net *.servicebus.windows.net *.table.core.windows.net'
57+
'*.redhat.com redhat.com redhat.io *.redhat.io'
58+
'graph.microsoft.com'
59+
'*.github.com github.com *.githubusercontent.com'
60+
'gitlab.com *.gitlab.com *.gitlab.io'
61+
'*.pagerduty.com pagerduty.com'
62+
'quay.io *.quay.io'
63+
'*.okta.com *.mtls.okta.com *.oktapreview.com *.mtls.oktapreview.com *.oktacdn.com *.okta-emea.com *.mtls.okta-emea.com *.kerberos.okta.com *.kerberos.okta-emea.com *.kerberos.oktapreview.com *.okta-gov.com *.mtls.okta-gov.com *.okta.mil *.mtls.okta.mil *.awsglobalaccelerator.com'
64+
'auth0.com *.auth0.com'
65+
'*.atlassian.com atlassian.com'
66+
'*.pndsn.com *.cloudfront.net *.wp.com *.gravatar.com *.googleapis.com'
67+
)
68+
69+
check_prerequisites() {
70+
print_status 'Checking prerequisites'
71+
if ! command -v az > /dev/null 2>&1; then
72+
print_error 'Azure CLI is not installed.'
73+
exit 1
74+
fi
75+
if ! az account show > /dev/null 2>&1; then
76+
print_error "Not logged in to Azure. Run 'az login' first."
77+
exit 1
78+
fi
79+
}
80+
81+
check_firewall() {
82+
print_status "Checking firewall: ${FIREWALL_NAME}"
83+
if ! az network firewall show \
84+
--resource-group "$RESOURCE_GROUP" \
85+
--name "$FIREWALL_NAME" > /dev/null; then
86+
print_error "Firewall '${FIREWALL_NAME}' not found in resource group '${RESOURCE_GROUP}'."
87+
exit 1
88+
fi
89+
}
90+
91+
check_existing_rule_collection() {
92+
print_status "Checking rule collection: ${RULE_COLLECTION_NAME}"
93+
if ! az network firewall application-rule collection show \
94+
--resource-group "$RESOURCE_GROUP" \
95+
--firewall-name "$FIREWALL_NAME" \
96+
--collection-name "$RULE_COLLECTION_NAME" > /dev/null 2>&1; then
97+
print_status "Rule collection '${RULE_COLLECTION_NAME}' does not exist."
98+
return
99+
fi
100+
101+
print_warning "Rule collection '${RULE_COLLECTION_NAME}' already exists."
102+
read -r -p 'Overwrite it? (y/N): ' -n 1 REPLY || REPLY=''
103+
printf '\n'
104+
if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then
105+
print_status 'Operation cancelled.'
106+
exit 0
107+
fi
108+
109+
print_status "Removing existing rule collection: ${RULE_COLLECTION_NAME}"
110+
az network firewall application-rule collection delete \
111+
--resource-group "$RESOURCE_GROUP" \
112+
--firewall-name "$FIREWALL_NAME" \
113+
--collection-name "$RULE_COLLECTION_NAME"
114+
}
115+
116+
create_application_rule() {
117+
local rule_name="$1"
118+
local target_definition="$2"
119+
local rule_index="$3"
120+
local -a target_fqdns
121+
local -a command
122+
123+
read -r -a target_fqdns <<< "$target_definition"
124+
command=(
125+
az network firewall application-rule create
126+
--resource-group "$RESOURCE_GROUP"
127+
--firewall-name "$FIREWALL_NAME"
128+
--collection-name "$RULE_COLLECTION_NAME"
129+
--name "$rule_name"
130+
--target-fqdns "${target_fqdns[@]}"
131+
--source-addresses "${SOURCE_ADDRESSES[@]}"
132+
--protocols "${PROTOCOLS[@]}"
133+
)
134+
135+
if [[ "$rule_index" -eq 0 ]]; then
136+
command+=(--action Allow --priority 200)
137+
fi
138+
139+
print_status "Adding firewall rule: ${rule_name}"
140+
"${command[@]}"
141+
}
142+
143+
create_rule_collection() {
144+
print_status "Creating firewall rule collection: ${RULE_COLLECTION_NAME}"
145+
if [[ "${#RULE_NAMES[@]}" -ne "${#RULE_TARGETS[@]}" ]]; then
146+
print_error 'Firewall rule names and target definitions are out of sync.'
147+
exit 1
148+
fi
149+
150+
for rule_index in "${!RULE_NAMES[@]}"; do
151+
create_application_rule \
152+
"${RULE_NAMES[$rule_index]}" \
153+
"${RULE_TARGETS[$rule_index]}" \
154+
"$rule_index"
155+
done
156+
}
157+
158+
check_prerequisites
159+
check_firewall
160+
check_existing_rule_collection
161+
create_rule_collection
162+
print_status "Rule collection '${RULE_COLLECTION_NAME}' created successfully."

0 commit comments

Comments
 (0)