Skip to content

Commit ed10da2

Browse files
committed
Many fixes to content
1 parent e75d4c3 commit ed10da2

File tree

2 files changed

+305
-1
lines changed

2 files changed

+305
-1
lines changed

AKS-Arc/TOC.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@
107107
- name: Restrict SSH access
108108
href: restrict-ssh-access.md
109109
- name: Deploy and configure Workload Identity
110-
href: workload-identity.md
110+
href: workload-identity.md
111+
- name: Validate signed container images
112+
href: validate-signed-container-images.md
111113
- name: Storage
112114
href: concepts-storage.md
113115
items:
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
---
2+
title: Validate Signed Container Images for AKS on Azure Local
3+
description: Learn how to validate signed container images for AKS on Azure Local deployments to ensure image integrity and prevent supply chain attacks.
4+
author: sethmanheim
5+
ms.topic: concept-article
6+
ms.date: 07/11/2025
7+
ms.author: sethm
8+
ms.reviewer: leslielin
9+
---
10+
11+
# How-to: validate signed container images for AKS on Azure Local deployments
12+
13+
[!INCLUDE [hci-applies-to-23h2](includes/hci-applies-to-23h2.md)]
14+
15+
Container image signing verifies the integrity and authenticity of images before deployment, ensuring a trusted infrastructure. This verification is vital in production environments, regulated industries, and automated CI/CD pipelines, where validating image sources helps prevent supply chain attacks and maintain compliance.
16+
17+
This article describes how to validate signed container images for AKS on Azure Local deployments.
18+
19+
## Prerequisites
20+
21+
Before you begin, ensure you have the following prerequisites:
22+
23+
1. **Cluster configuration:** Deploy an AKS Arc cluster with these requirements
24+
25+
- One control plane node.
26+
- At least one Linux node.
27+
- (Optional) Add a Windows node pool if you need to validate Windows container images.
28+
29+
1. **A Windows machine Jump Box** is required to run the image validation script. The machine must meet these prerequisites:
30+
31+
- **Network access**: The Jump Box must be able to communicate with the Azure Local physical boxes where the AKS Arc cluster is deployed and route traffic to the IP addresses assigned to the AKS Arc cluster, including all control plane and worker nodes.
32+
- **Required tools installed**: Install these tools on the Jump Box: **curl**, **ssh**, and **scp**. These tools enable secure remote access, file transfers, and HTTP-based interactions with your cluster or management endpoints.
33+
- **SSH access**: The private SSH key used during cluster creation must be present on the Jump Box.
34+
- This key enables connections to individual nodes (Linux or Windows).
35+
- For details on generating or retrieving the key, see [Configure SSH keys for a cluster](/azure/aks/aksarc/configure-ssh-keys).
36+
37+
1. **Install the Kubernetes CLI**
38+
39+
You can use the Kubernetes CLI, [kubectl](https://kubernetes.io/docs/reference/kubectl/), to connect to your Kubernetes cluster. If you use Azure Cloud Shell, kubectl is already installed. If you run the commands locally, you can use the Azure CLI or Azure PowerShell to install kubectl.
40+
41+
# [Azure CLI](#tab/cli)
42+
43+
Install kubectl locally using the [az aks install-cli](/cli/azure/aks?view=azure-cli-latest#az-aks-install-cli) command.
44+
45+
# [PowerShell](#tab/powershell)
46+
47+
Install kubectl locally using the [Install-AzAksCliTool](/powershell/module/az.aks/install-azaksclitool?view=azps-14.2.0) cmdlet.
48+
49+
---
50+
51+
## Step 1: download the image validation script
52+
53+
1. Open an administrative PowerShell window and create a temporary folder at **c:\imagesign**:
54+
55+
```powershell
56+
mkdir c:\imagesign
57+
cd c:\imagesign
58+
```
59+
60+
1. Run the following commands to download the [prerequisite.ps1](https://raw.githubusercontent.com/Azure/aksArc/refs/heads/main/scripts/ImageSignValidation/prerequisite.ps1) script to the Jump Box and save it in **c:\imagesign**:
61+
62+
```powershell
63+
$giturl = "https://raw.githubusercontent.com/Azure/aksArc/refs/heads/main/scripts/ImageSignValidation/prerequisite.ps1"
64+
Invoke-WebRequest -Uri $giturl -OutFile C:\imagesign\prerequisite.ps1 -UseBasicParsing
65+
Unblock-File .\prerequisite.ps1
66+
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
67+
```
68+
69+
1. Execute the script
70+
71+
```powershell
72+
.\prerequisite.ps1
73+
```
74+
75+
Sample output:
76+
77+
```output
78+
2025-05-10 00:39:27 [INFO] The current folder is C:\imagesign
79+
2025-05-10 00:39:27 [INFO] Linux folder location is C:\imagesign\linux
80+
2025-05-10 00:39:28 [INFO] Executable not found at C:\imagesign\linux\notation. Proceeding with download and extraction.
81+
2025-05-10 00:39:28 [INFO] Downloading file from https://github.com/notaryproject/notation/releases/download/v1.3.1/notation_1.3.1_linux_amd64.tar.gz
82+
2025-05-10 00:39:36 [INFO] Extracting file to C:\imagesign\linux
83+
2025-05-10 00:39:36 [INFO] Downloading certificate from https://www.microsoft.com/pkiops/certs/Microsoft%20Supply%20Chain%20RSA%20Root%20CA%202022.crt
84+
2025-05-10 00:39:36 [INFO] Certificate downloaded to C:\imagesign\linux\ca.crt
85+
2025-05-10 00:39:36 [INFO] Downloading certificate from http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt
86+
2025-05-10 00:39:36 [INFO] Certificate downloaded to C:\imagesign\linux\tsa.crt
87+
2025-05-10 00:39:36 [INFO] Windows folder location is C:\imagesign\win
88+
2025-05-10 00:39:36 [INFO] Executable not found at C:\imagesign\win\notation.exe. Proceeding with download and extraction.
89+
2025-05-10 00:39:36 [INFO] Downloading file from https://github.com/notaryproject/notation/releases/download/v1.3.1/notation_1.3.1_windows_amd64.zip
90+
2025-05-10 00:39:44 [INFO] Extracting file to C:\imagesign\win
91+
2025-05-10 00:39:44 [INFO] Downloading certificate from https://www.microsoft.com/pkiops/certs/Microsoft%20Supply%20Chain%20RSA%20Root%20CA%202022.crt
92+
2025-05-10 00:39:44 [INFO] Certificate downloaded to C:\imagesign\win\ca.crt
93+
2025-05-10 00:39:44 [INFO] Downloading certificate from http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt
94+
2025-05-10 00:39:44 [INFO] Certificate downloaded to C:\imagesign\win\tsa.crt
95+
```
96+
97+
1. Two folders will be created: **linux** for Linux files and **win** for Windows files.
98+
99+
### [Linux](#tab/linux)
100+
101+
Copy **LinuxImageValidate.py** to the **c:\imagesign\linux** folder:
102+
103+
```powershell
104+
$giturllinux = "https://raw.githubusercontent.com/Azure/aksArc/refs/heads/main/scripts/ImageSignValidation/LinuxImageValidate.py"
105+
Invoke-WebRequest -Uri $giturllinux -OutFile C:\imagesign\linux\LinuxImageValidate.py -UseBasicParsing
106+
Unblock-File C:\imagesign\linux\LinuxImageValidate.py
107+
```
108+
109+
### [Windows](#tab/windows)
110+
111+
Copy **WindowsImageValidate.ps1** to the **c:\imagesign\win** folder:
112+
113+
```powershell
114+
$giturlwin = "https://raw.githubusercontent.com/Azure/aksArc/refs/heads/main/scripts/ImageSignValidation/WindowsImageValidate.ps1"
115+
Invoke-WebRequest -Uri $giturlwin -OutFile C:\imagesign\win\WindowsImageValidate.ps1 -UseBasicParsing
116+
Unblock-File C:\imagesign\win\WindowsImageValidate.ps1
117+
Invoke-WebRequest -Uri $giturlwin -OutFile C:\imagesign\win\WindowsImageValidate.py -UseBasicParsing
118+
Unblock-File C:\imagesign\win\WindowsImageValidate.py
119+
```
120+
121+
---
122+
123+
## Step 2: Get the control plane and worker node IP addresses
124+
125+
Follow steps 1 and 2 in the [Use SSH to connect to worker nodes](ssh-connect-to-windows-and-linux-worker-nodes.md#use-ssh-to-connect-to-worker-nodes) section to obtain IP addresses.
126+
127+
### Sample command
128+
129+
```powershell
130+
kubectl --kubeconfig /path/to/aks-cluster-kubeconfig get nodes -o wide
131+
```
132+
133+
Sample output:
134+
135+
```output
136+
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
137+
moc-lsbe393il9d Ready control-plane 3h14m v1.30.4 100.72.248.133 <none> CBL-Mariner/Linux 5.15.173.1-2.cm2 containerd://1.6.26
138+
moc-lzwagtkjah5 Ready <none> 3h12m v1.30.4 100.72.248.134 <none> CBL-Mariner/Linux 5.15.173.1-2.cm2 containerd://1.6.26
139+
moc-wlcjnwn5n02 Ready <none> 14m v1.30.4 100.72.248.135 <none> Windows Server 2022 Datacenter 10.0.20348.2700 containerd://1.6.21+azure
140+
```
141+
142+
From this sample output:
143+
144+
- Control plane IP is 100.72.248.133 (where the ROLES value is `control-plane` and OS image is `CBL-Mariner/Linux`).
145+
- Linux node IP is 100.72.248.134 (where the ROLES value is `none` and OS image is `CBL-Mariner/Linux`).
146+
- Windows node IP is 100.72.248.135 (where the OS image is `Windows Server 2022`).
147+
148+
## Step 3: run the image validation script on the control plane and worker nodes
149+
150+
### [Linux](#tab/linux)
151+
152+
These steps work for both the control plane node and Linux worker node since they use the **CBL-Mariner/Linux** OS image.
153+
154+
1. Check if the commands can be run on the Linux VM (assuming the private key is in **C:\Users\Administrator\.ssh**):
155+
156+
```bash
157+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" -o StrictHostKeyChecking=no [email protected] "sudo crictl images --no-trunc"
158+
```
159+
160+
1. Copy the Linux-specific files to the Linux VM:
161+
162+
```bash
163+
scp -i "C:\Users\Administrator\.ssh\id_rsa" C:\imagesign\linux\* [email protected]:.
164+
```
165+
166+
1. Mark the notation binary file as executable:
167+
168+
```bash
169+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" -o StrictHostKeyChecking=no [email protected] "sudo chmod +x notation"
170+
```
171+
172+
1. Execute commands to validate image signature verification. This step can take around 2-5 minutes:
173+
174+
```bash
175+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" -o StrictHostKeyChecking=no [email protected] "sudo python3 LinuxImageValidate.py"
176+
```
177+
178+
1. Copy the output file to the local directory:
179+
180+
```bash
181+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" -o StrictHostKeyChecking=no [email protected] "sudo cat imagevalidation_results_linux.json" > imagevalidation_results_controlplane.json
182+
```
183+
184+
1. Clean up all files copied to the VM:
185+
186+
```bash
187+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" -o StrictHostKeyChecking=no [email protected] rm LinuxImageValidate.py notation tsa.crt ca.crt LICENSE imagevalidation_results_linux.json results.yaml
188+
```
189+
190+
1. Clean up the IP reference from the SSH cache:
191+
192+
```bash
193+
ssh-keygen -R 100.72.248.133
194+
```
195+
196+
Sample output:
197+
198+
```output
199+
{
200+
"failed_signed_images": [
201+
"mcr.microsoft.com/mssql/server:2017-latest",
202+
"mcr.microsoft.com/oss/kubernetes/coredns:v1.9.3",
203+
"mcr.microsoft.com/oss/kubernetes/pause:3.9"
204+
],
205+
"passed_signed_images": [
206+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.28.3",
207+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.28.5",
208+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.28.9",
209+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.29.2",
210+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.29.4",
211+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.29.7",
212+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.29.9",
213+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.30.3",
214+
"mcr.microsoft.com/oss/kubernetes/kube-proxy:v1.30.4",
215+
"mcr.microsoft.com/oss/kubernetes/kube-rbac-proxy:v0.18.1",
216+
"mcr.microsoft.com/oss/kubernetes/kube-scheduler:v1.28.12-hotfix.20240719",
217+
"mcr.microsoft.com/oss/kubernetes/kube-scheduler:v1.28.14-hotfix.20240918",
218+
"mcr.microsoft.com/oss/kubernetes/kube-scheduler:v1.29.7",
219+
"mcr.microsoft.com/oss/kubernetes/kube-scheduler:v1.29.9",
220+
"mcr.microsoft.com/oss/kubernetes/kube-scheduler:v1.30.3",
221+
"mcr.microsoft.com/oss/kubernetes/kube-scheduler:v1.30.4",
222+
"mcr.microsoft.com/oss/kubernetes/pause:3.9-hotfix-20230808",
223+
"mcr.microsoft.com/oss/v2/kubernetes-csi/csi-driver-nfs:v4.9.0-1"
224+
]
225+
}
226+
```
227+
228+
> [!NOTE]
229+
> If the **failed_signed_images** list is empty, all images are signed correctly. Otherwise, the list shows images that failed signature verification.
230+
231+
### [Windows](#tab/windows)
232+
233+
These steps work on all supported Windows OS worker nodes.
234+
235+
1. Check if the commands can be run on the Windows VM (assuming the private key is in folder **C:\Users\Administrator\.ssh**):
236+
237+
```bash
238+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" -o StrictHostKeyChecking=no [email protected] "crictl images --no-trunc"
239+
```
240+
241+
1. Copy the Windows-specific files inside the Windows VM:
242+
243+
```bash
244+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" [email protected] "powershell -ExecutionPolicy Bypass mkdir c:\win"
245+
scp -i "C:\Users\Administrator\.ssh\id_rsa" C:\imagesign\win\ca.crt [email protected]:c:\win\ca.crt
246+
scp -i "C:\Users\Administrator\.ssh\id_rsa" C:\imagesign\win\notation.exe [email protected]:c:\win\notation.exe
247+
scp -i "C:\Users\Administrator\.ssh\id_rsa" C:\imagesign\win\tsa.crt [email protected]:c:\win\tsa.crt
248+
scp -i "C:\Users\Administrator\.ssh\id_rsa" C:\imagesign\win\WindowsImageValidate.ps1 [email protected]:c:\win\WindowsImageValidate.ps1
249+
```
250+
251+
1. Execute commands to validate image signature verification. This step can take around 2-5 minutes:
252+
253+
```bash
254+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" [email protected] "powershell -ExecutionPolicy Bypass -File c:\win\WindowsImageValidate.ps1"
255+
```
256+
257+
1. Copy the output file to the local directory:
258+
259+
```bash
260+
scp -i "C:\Users\Administrator\.ssh\id_rsa" [email protected]:c:\win\imagevalidation_results_windows.json C:\imagesign\imagevalidation_results_windows.json
261+
```
262+
263+
1. Clean up all files copied to the VM:
264+
265+
```bash
266+
ssh -i "C:\Users\Administrator\.ssh\id_rsa" [email protected] "powershell -ExecutionPolicy Bypass remove-item -force c:\win"
267+
```
268+
269+
1. Clean up IP reference from the SSH cache:
270+
271+
```bash
272+
ssh-keygen -R 100.72.248.135
273+
```
274+
275+
Sample output:
276+
277+
```output
278+
{
279+
"failed_signed_images": [
280+
],
281+
"passed_signed_images": [
282+
"mcr.microsoft.com/oss/kubernetes-csi/livenessprobe@sha256:20fd8754d36efc52ff0a837e646909102be5d47600a8656804aecd4eff52b7c7",
283+
"mcr.microsoft.com/oss/kubernetes/pause@sha256:2b5d81a9d7f04299f45ed1b6822de018188f463914fcbf5592f39087c9adead1",
284+
"mcr.microsoft.com/windows/nanoserver@sha256:f82cb05e20c4bfa93a007c9f073f83febd8bc6d16f98a3208f3baa486aafcdf4"
285+
],
286+
"failed_signed_images": [
287+
]
288+
}
289+
```
290+
291+
> [!NOTE]
292+
> If the **failed_signed_images** list is empty, all images are signed correctly. Otherwise, the list shows images that failed signature verification.
293+
294+
---
295+
296+
## Next steps
297+
298+
For more information about AKS on Azure Local, see the following articles:
299+
300+
- [AKS on Azure Local overview](/azure/aks/overview)
301+
- [Deploying AKS on Azure Local](/azure/aks/cluster-configuration)
302+
- [Managing AKS on Azure Local](/azure/aks/cluster-management)

0 commit comments

Comments
 (0)