Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions src/confcom/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Release History
===============

2.4.0
+++++
* Add MacOS support for Linux-container policy generation

2.3.0
+++++
* Add an option to include the kube-proxy image-attached fragment in Linux VN2 policies
Expand Down
31 changes: 15 additions & 16 deletions src/confcom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [Prerequisites](#prerequisites)
- [Installation Instructions (End User)](#installation-instructions-end-user)
- [Current Limitations](#current-limitations)
- [Platform Support (Linux and Windows Policies)](#platform-support-linux-and-windows-policies)
- [Trademarks](#trademarks)

## Repository
Expand All @@ -13,21 +14,18 @@

## Prerequisites

**MacOS** is **NOT** supported yet
**MacOS** is supported for Linux-container policy generation. Native Darwin binaries for `dmverity-vhd` (integrity-vhd v2.3) and `sign1util` (cosesign1go v1.7.0) are included in the extension package.

- **64-bit** `Python 3.6+` and `pip`
- **64-bit** **Windows 10** or later
- Install python3 version 3.6+ through [official download](https://www.python.org/downloads/)
- or chocolatey: `choco install python`
- Or **64-bit** Linux Distribution System, **Ubuntu 18.04** or later is recommended
- Ubuntu 18.04 or later comes with python 3.6+ by default
- Docker Daemon
- Linux(Ubuntu):

```bash
sudo apt install docker.io
```

- **64-bit** MacOS on Apple Silicon or Intel
- Container runtime: Docker
- Docker must be running when generating Linux policies from container images.
- Docker is not required when all image layers are supplied with `--tar`.
- Windows: [Docker Desktop](https://www.docker.com/products/docker-desktop) and [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install)
- **CimWriter.dll** (Windows only, for Windows container support)
- Required for generating security policies for Windows containers
Expand All @@ -36,7 +34,7 @@
## Installation Instructions (End User)

1. Install Azure CLI through following ways:
1. Option 1: (Windows and Linux) use `PyPI/pip(comes with 64-bit python)` to install `azure-cli`
1. Option 1: (Windows, Linux, and MacOS) use `PyPI/pip(comes with 64-bit python)` to install `azure-cli`

```bash
python3 -m pip install azure-cli
Expand All @@ -62,18 +60,19 @@ The `confcom` extension does not currently support:

## Platform Support (Linux and Windows Policies)

The `--platform` parameter controls whether policies are generated for Linux (`linux/amd64`, the default) or Windows (`windows/amd64`) containers.
The `--platform` parameter controls whether policies are generated for Linux (`linux/amd64`, the default) or Windows (`windows/amd64`) containers. On macOS, only Linux-container policies are supported.

Docker must be running when generating Linux policies from container images. It is not required when all image layers are supplied with `--tar`.

**Docker Desktop must be running in the matching container mode** to produce correct layer hashes:
Windows policies require Docker in Windows-container mode:

| Policy Target | Docker Container Mode | Where to Run |
| Policy Target | Container Runtime Mode | Where to Run |
|---|---|---|
| Linux (`--platform linux/amd64`) | Linux containers | WSL or PowerShell |
| Windows (`--platform windows/amd64`) | Windows containers | PowerShell only |
| Linux (`--platform linux/amd64`) | Docker, Linux containers | Linux, WSL, PowerShell, or macOS |
| Windows (`--platform windows/amd64`) | Docker, Windows containers | PowerShell only |

- **Windows policies cannot be generated from WSL**, because Windows layer hashing (CIMfs) requires Windows APIs.
- **Linux policies can be generated from either WSL or PowerShell**, as long as Docker Desktop is in Linux containers mode.
- Running with the wrong Docker container mode may produce **incorrect layer hashes** that will cause the container to be rejected at runtime.
- Running with the wrong container runtime mode may produce **incorrect layer hashes** that will cause the container to be rejected at runtime.

## Trademarks

Expand Down
4 changes: 2 additions & 2 deletions src/confcom/azext_confcom/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@

- name: --platform
type: string
short-summary: 'Target platform for policy generation (linux/amd64 or windows/amd64). Defaults to linux/amd64. Docker Desktop must be running in the matching container mode to produce correct layer hashes.'
short-summary: 'Target platform for policy generation (linux/amd64 or windows/amd64). Defaults to linux/amd64. Docker must be running for Linux image workflows; it is not required when all image layers are supplied with --tar. Docker in Windows-container mode is required for Windows policies.'

- name: --allow-kubeproxy
type: boolean
Expand All @@ -120,7 +120,7 @@
text: az confcom acipolicygen --template-file "./template.json" --outraw-pretty-print
- name: Input an ARM Template file to save a Confidential Container Security Policy to a file as base64 encoded text
text: az confcom acipolicygen --template-file "./template.json" -s "./output-file.txt" --print-policy
- name: Input an ARM Template file and use a tar file as the image source instead of the Docker daemon
- name: Input an ARM Template file and use a tar file as the image source instead of the container runtime
text: az confcom acipolicygen --template-file "./template.json" --tar "./image.tar"
- name: Input an ARM Template file and use a fragments JSON file to generate a policy
text: az confcom acipolicygen --template-file "./template.json" --fragments-json "./fragments.json" --include-fragments
Expand Down
6 changes: 3 additions & 3 deletions src/confcom/azext_confcom/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ def load_arguments(self, _):
required=False,
default="linux/amd64",
help="Target platform for policy generation. Defaults to linux/amd64. "
"Note: Docker Desktop must be running in the matching container mode "
"(Linux containers for linux/amd64, Windows containers for windows/amd64) "
"to produce correct layer hashes.",
"Docker must be running for Linux image workflows; it is not "
"required when all image layers are supplied with --tar. Docker in "
"Windows-container mode is required for Windows policies.",
choices=["linux/amd64", "windows/amd64"],
)
c.argument(
Expand Down
19 changes: 17 additions & 2 deletions src/confcom/azext_confcom/cose_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@
"url": "https://github.com/microsoft/cosesign1go/releases/download/v1.4.0/sign1util.exe",
"sha256": "f33cccf2b1bb8c3a495c730984b47d0f0715678981dbfe712248a2452dd53303",
},
"Darwin-arm64": {
"path": _binaries_dir / "sign1util-darwin-arm64",
"url": "https://github.com/microsoft/cosesign1go/releases/download/v1.7.0/sign1util-darwin-arm64",
"sha256": "c0c89b54f42e33317127697936a8eed70281934d4546acfc1446e588fcf2fe69",
},
"Darwin-amd64": {
"path": _binaries_dir / "sign1util-darwin-amd64",
"url": "https://github.com/microsoft/cosesign1go/releases/download/v1.7.0/sign1util-darwin-amd64",
"sha256": "82168735a472002faca5ffad5342eeda3c307d06e892cd851c64766d5aa02049",
},
}


Expand Down Expand Up @@ -75,10 +85,15 @@ def __init__(self):
elif host_os == "Windows":
DEFAULT_LIB += ".exe"
elif host_os == "Darwin":
eprint("The extension for MacOS has not been implemented.")
if machine == "arm64":
DEFAULT_LIB += "-darwin-arm64"
elif machine in ("x86_64", "amd64"):
DEFAULT_LIB += "-darwin-amd64"
else:
eprint(f"Unsupported MacOS architecture: {machine}.")
Comment on lines +88 to +93
else:
eprint(
"Unknown target platform. The extension only works with Windows and Linux"
"Unknown target platform. The extension only works with Windows, Linux, and Darwin"
)

self.policy_bin = os.path.join(f"{script_directory}", f"{DEFAULT_LIB}")
Expand Down
5 changes: 2 additions & 3 deletions src/confcom/azext_confcom/lib/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import logging
import subprocess
import docker
from azext_confcom.rootfs_proxy import get_dmverity_vhd_path

from pathlib import Path

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -57,8 +57,7 @@ def get_image_platform(image_reference: str) -> str:

def get_image_layers(image: str, platform: str = "linux/amd64") -> list[str]:

binary_path = Path(__file__).parent.parent / "bin" / "dmverity-vhd"

binary_path = get_dmverity_vhd_path()
get_image(image)

arg_list = [binary_path.as_posix(), "-d", "roothash", "-i", image]
Expand Down
64 changes: 40 additions & 24 deletions src/confcom/azext_confcom/rootfs_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import stat
import subprocess
import sys
from pathlib import Path
from typing import List, Dict

import requests
Expand Down Expand Up @@ -39,14 +40,24 @@
# Linux
{
"path": _binaries_dir / "dmverity-vhd",
"url": f"{_INTEGRITY_VHD_RELEASE_URL}/dmverity-vhd",
"sha256": "85b383bcce609e7acf0b0eae4b6e214d795b30c4d9d96c21377ab97ea3161a28",
"url": "https://github.com/microsoft/integrity-vhd/releases/download/v2.3/dmverity-vhd",
"sha256": "0f10df304f9a4b77a371aba2f500cd7a19cb547bca5e9cd2b921803f5e67080f",
},
# Windows
{
"path": _binaries_dir / "dmverity-vhd.exe",
"url": f"{_INTEGRITY_VHD_RELEASE_URL}/dmverity-vhd.exe",
"sha256": "83681d2e26b8406098e06e24db80c8eaf7b17eee08a5f8b313c88620f0612b66",
"url": "https://github.com/microsoft/integrity-vhd/releases/download/v2.3/dmverity-vhd.exe",
"sha256": "c3652fb1a4ce1155c388e0e2f7db6b2b985e0ad6da7db062ce82a00bb2b6b6f8",
},
{
"path": _binaries_dir / "dmverity-vhd-darwin-arm64",
"url": "https://github.com/microsoft/integrity-vhd/releases/download/v2.3/dmverity-vhd-darwin-arm64",
"sha256": "e7174315c8df15ceb59120d720b63cb62f7cbd1ec6cb3b13436370da72c792be",
},
{
"path": _binaries_dir / "dmverity-vhd-darwin-amd64",
"url": "https://github.com/microsoft/integrity-vhd/releases/download/v2.3/dmverity-vhd-darwin-amd64",
"sha256": "4cb5a2970030b120370afd03b25b12605343fd098c4ce539f9f117a17fc2112d",
},
{
"path": _binaries_dir / "CimWriter.dll",
Expand All @@ -61,6 +72,30 @@
]


def get_dmverity_vhd_path() -> Path:
"""Return the host-specific dmverity-vhd binary path."""
binary_name = "dmverity-vhd"

if host_os == "Windows":
if machine.endswith("64"):
binary_name += ".exe"
else:
eprint("32-bit Windows is not supported.")
elif host_os == "Darwin":
if machine == "arm64":
binary_name += "-darwin-arm64"
elif machine in ("x86_64", "amd64"):
binary_name += "-darwin-amd64"
Comment on lines +84 to +88
else:
eprint(f"Unsupported MacOS architecture: {machine}.")
elif host_os != "Linux":
eprint(
"Unknown target platform. The extension only works with Windows, Linux, and Darwin"
)

return Path(__file__).parent / "bin" / binary_name


class SecurityPolicyProxy: # pylint: disable=too-few-public-methods
# static variable to cache layer hashes between container groups
layer_cache = {}
Expand All @@ -78,26 +113,7 @@ def download_binaries():
f.write(dmverity_vhd_fetch_resp.content)

def __init__(self):
script_directory = os.path.dirname(os.path.realpath(__file__))
DEFAULT_LIB = "./bin/dmverity-vhd"

if host_os == "Linux":
pass
elif host_os == "Windows":
if machine.endswith("64"):
DEFAULT_LIB += ".exe"
else:
eprint(
"32-bit Windows is not supported."
)
elif host_os == "Darwin":
eprint("The extension for MacOS has not been implemented.")
else:
eprint(
"Unknown target platform. The extension only works with Windows and Linux"
)

self.policy_bin = os.path.join(f"{script_directory}", f"{DEFAULT_LIB}")
self.policy_bin = str(get_dmverity_vhd_path())

# check if the extension binary exists
if not os.path.exists(self.policy_bin):
Expand Down
80 changes: 80 additions & 0 deletions src/confcom/azext_confcom/tests/latest/test_confcom_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import subprocess
import unittest
from pathlib import Path
from unittest import mock

from azext_confcom import cose_proxy, rootfs_proxy
from azext_confcom.lib import images


class TestDarwinBinarySelection(unittest.TestCase):
def test_dmverity_binary_selection(self):
for machine, expected in (
("arm64", "dmverity-vhd-darwin-arm64"),
("x86_64", "dmverity-vhd-darwin-amd64"),
("amd64", "dmverity-vhd-darwin-amd64"),
):
with self.subTest(machine=machine):
with mock.patch.object(rootfs_proxy, "host_os", "Darwin"), \
mock.patch.object(rootfs_proxy, "machine", machine), \
mock.patch.object(rootfs_proxy.os.path, "exists", return_value=True), \
mock.patch.object(rootfs_proxy.os, "access", return_value=True):
self.assertEqual(
Path(rootfs_proxy.SecurityPolicyProxy().policy_bin).name,
expected,
)

def test_cose_binary_selection(self):
for machine, expected in (
("arm64", "sign1util-darwin-arm64"),
("x86_64", "sign1util-darwin-amd64"),
("amd64", "sign1util-darwin-amd64"),
):
with self.subTest(machine=machine):
with mock.patch.object(cose_proxy, "host_os", "Darwin"), \
mock.patch.object(cose_proxy, "machine", machine), \
mock.patch.object(cose_proxy.os.path, "exists", return_value=True), \
mock.patch.object(cose_proxy.os, "access", return_value=True):
self.assertEqual(
Path(cose_proxy.CoseSignToolProxy().policy_bin).name,
expected,
)

def test_unsupported_dmverity_architecture(self):
with mock.patch.object(rootfs_proxy, "host_os", "Darwin"), \
mock.patch.object(rootfs_proxy, "machine", "powerpc64"):
with self.assertRaises(SystemExit) as exception:
rootfs_proxy.get_dmverity_vhd_path()
self.assertEqual(exception.exception.code, 1)

def test_unsupported_cose_architecture(self):
with mock.patch.object(cose_proxy, "host_os", "Darwin"), \
mock.patch.object(cose_proxy, "machine", "powerpc64"):
with self.assertRaises(SystemExit) as exception:
cose_proxy.CoseSignToolProxy()
self.assertEqual(exception.exception.code, 1)

@mock.patch.object(images, "get_image")
@mock.patch.object(images.subprocess, "run")
@mock.patch.object(images, "get_dmverity_vhd_path")
def test_image_layer_hashing_uses_host_binary(self, get_binary_path, run, get_image):
binary_path = Path("/tmp/dmverity-vhd-darwin-arm64")
get_binary_path.return_value = binary_path
run.return_value = subprocess.CompletedProcess(
args=[],
returncode=0,
stdout="Layer 0 root hash: abc123\n",
)

self.assertEqual(images.get_image_layers("image:tag"), ["abc123"])
self.assertEqual(run.call_args[0][0][0], binary_path.as_posix())
get_image.assert_called_once_with("image:tag")


if __name__ == "__main__":
unittest.main()
18 changes: 11 additions & 7 deletions src/confcom/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

logger.warn("Wheel is not available, disabling bdist_wheel hook")

VERSION = "2.3.0"
VERSION = "2.4.0"

# The full list of classifiers is available at
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
Expand Down Expand Up @@ -69,14 +69,18 @@
package_data={
"azext_confcom": [
"azext_metadata.json",
"bin/dmverity-vhd.exe", # windows for ACI
"bin/dmverity-vhd", # linux for ACI
"bin/dmverity-vhd.exe", # Windows for ACI
"bin/dmverity-vhd", # Linux for ACI
"bin/dmverity-vhd-darwin-arm64", # Apple Silicon for ACI
"bin/dmverity-vhd-darwin-amd64", # Intel Mac for ACI
Comment on lines +74 to +75
"bin/CimWriter.dll", # C-WCOW cimwriter.dll
"bin/CimWriter.LICENSE.pdf", # C-WCOW cimwriter.dll license
"bin/genpolicy-windows.exe", # windows for AKS
"bin/genpolicy-linux", # linux for AKS
"bin/sign1util.exe", # windows for cose tool
"bin/sign1util", # linux for cose tool
"bin/genpolicy-windows.exe", # Windows for AKS
"bin/genpolicy-linux", # Linux for AKS
"bin/sign1util.exe", # Windows for cose tool
"bin/sign1util", # Linux for cose tool
"bin/sign1util-darwin-arm64", # Apple Silicon for cose tool
"bin/sign1util-darwin-amd64", # Intel Mac for cose tool
"data/*",
]
},
Expand Down