diff --git a/src/confcom/HISTORY.rst b/src/confcom/HISTORY.rst index 5c8c7d2bc04..f670398fde8 100644 --- a/src/confcom/HISTORY.rst +++ b/src/confcom/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +1.4.2 +++++++ +* Update policy model to use pydantic and explicitly declare collections where order doesn't affect function. These fields will serialize in alphabetical order and comparisons will ignore order. + 1.4.0 ++++++ * Add --with-containers flag to acipolicygen and acifragmentgen to allow passing container policy definitions directly diff --git a/src/confcom/azext_confcom/lib/binaries.py b/src/confcom/azext_confcom/lib/binaries.py new file mode 100644 index 00000000000..3df0e5a231e --- /dev/null +++ b/src/confcom/azext_confcom/lib/binaries.py @@ -0,0 +1,13 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import os + + +def get_binaries_dir(): + binaries_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "bin") + if not os.path.exists(binaries_dir): + os.makedirs(binaries_dir) + return binaries_dir diff --git a/src/confcom/azext_confcom/lib/opa.py b/src/confcom/azext_confcom/lib/opa.py new file mode 100644 index 00000000000..a83e3920876 --- /dev/null +++ b/src/confcom/azext_confcom/lib/opa.py @@ -0,0 +1,54 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +import hashlib +import json +import os +from pathlib import Path +import platform +import subprocess +from typing import Iterable + +import requests + +from azext_confcom.lib.binaries import get_binaries_dir + +_opa_path = os.path.abspath(os.path.join(get_binaries_dir(), "opa")) +_expected_sha256 = "fe8e191d44fec33db2a3d0ca788b9f83f866d980c5371063620c3c6822792877" + + +def opa_get(): + + opa_fetch_resp = requests.get( + f"https://openpolicyagent.org/downloads/v1.10.1/opa_{platform.system().lower()}_amd64", + verify=True, + ) + opa_fetch_resp.raise_for_status() + + assert hashlib.sha256(opa_fetch_resp.content).hexdigest() == _expected_sha256 + + with open(_opa_path, "wb") as f: + f.write(opa_fetch_resp.content) + + os.chmod(_opa_path, 0o755) + return _opa_path + + +def opa_run(args: Iterable[str]) -> subprocess.CompletedProcess: + return subprocess.run( + [_opa_path, *args], + check=True, + stdout=subprocess.PIPE, + text=True, + ) + + +def opa_eval(data_path: Path, query: str): + return json.loads(opa_run([ + "eval", + "--format", "json", + "--data", str(data_path), + query, + ]).stdout.strip()) diff --git a/src/confcom/azext_confcom/lib/orderless_dataclasses.py b/src/confcom/azext_confcom/lib/orderless_dataclasses.py new file mode 100644 index 00000000000..88f6b66b192 --- /dev/null +++ b/src/confcom/azext_confcom/lib/orderless_dataclasses.py @@ -0,0 +1,64 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from typing import Any +from pydantic.dataclasses import dataclass as _dataclass, Field +from pydantic import field_serializer + + +# The policy model is represented as pydantic dataclasses, this makes +# serialisation to/from JSON trivial. + +# For some collections in the model, the order has no semantic meaning +# (e.g. environment rules). We mark such fields using a custom OrderlessField +# class which is an extension of the pydantic Field class. This custom class +# just sets a metadata flag we can read later. + +# We then also extend the dataclass decorator to sort these fields with this +# flag before serialisation and comparison. + + +def dataclass(cls=None, **dataclass_kwargs): + def wrap(inner_cls): + + # This method uses a pydantic field serializer to operate on fields + # before serialisation. Here we look for "orderless" fields and sort them. + @field_serializer("*") + def _sort_orderless(self, value, info): + field = type(self).__pydantic_fields__[info.field_name] + if (field.json_schema_extra or {}).get("orderless"): + return sorted(value, key=repr) + return value + setattr(inner_cls, "_sort_orderless", _sort_orderless) + + # This custom equality method sorts "orderless" fields before comparison. + def __eq__(self, other): + def compare_field(name, field_info): + if (field_info.json_schema_extra or {}).get("orderless"): + return ( + sorted(getattr(self, name), key=repr) == + sorted(getattr(other, name), key=repr) + ) + return getattr(self, name) == getattr(other, name) + + return ( + type(self) is type(other) and + all( + compare_field(name, field_info) + for name, field_info in self.__pydantic_fields__.items() + ) + ) + setattr(inner_cls, "__eq__", __eq__) + + return _dataclass(inner_cls, eq=False, **dataclass_kwargs) + + # This adds support for using the decorator with or without parentheses. + if cls is None: + return wrap + return wrap(cls) + + +def OrderlessField(**kwargs: Any): + return Field(json_schema_extra={"orderless": True}, **kwargs) diff --git a/src/confcom/azext_confcom/lib/policy.py b/src/confcom/azext_confcom/lib/policy.py index 354d5d687db..b7f8f7ed622 100644 --- a/src/confcom/azext_confcom/lib/policy.py +++ b/src/confcom/azext_confcom/lib/policy.py @@ -3,12 +3,12 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from dataclasses import dataclass, field -from typing import Literal, Optional +from typing import Literal, Optional, List +from azext_confcom.lib.orderless_dataclasses import dataclass, OrderlessField, Field def get_default_capabilities(): - return [ + return ( "CAP_AUDIT_WRITE", "CAP_CHOWN", "CAP_DAC_OVERRIDE", @@ -23,16 +23,16 @@ def get_default_capabilities(): "CAP_SETPCAP", "CAP_SETUID", "CAP_SYS_CHROOT" - ] + ) @dataclass class ContainerCapabilities: - ambient: list[str] = field(default_factory=list) - bounding: list[str] = field(default_factory=get_default_capabilities) - effective: list[str] = field(default_factory=get_default_capabilities) - inheritable: list[str] = field(default_factory=list) - permitted: list[str] = field(default_factory=get_default_capabilities) + ambient: List[str] = OrderlessField(default_factory=list) + bounding: List[str] = OrderlessField(default_factory=get_default_capabilities) + effective: List[str] = OrderlessField(default_factory=get_default_capabilities) + inheritable: List[str] = OrderlessField(default_factory=list) + permitted: List[str] = OrderlessField(default_factory=get_default_capabilities) @dataclass @@ -44,24 +44,26 @@ class ContainerRule: @dataclass class ContainerExecProcesses: - command: list[str] - signals: Optional[list[str]] = None + command: List[str] + signals: Optional[List[str]] = OrderlessField(default=None) allow_stdio_access: bool = True -@dataclass +@dataclass() class ContainerMount: destination: str source: str type: str - options: list[str] = field(default_factory=list) + options: List[str] = OrderlessField(default_factory=list) @dataclass class ContainerUser: - group_idnames: list[ContainerRule] = field(default_factory=lambda: [ContainerRule(pattern="", strategy="any")]) + group_idnames: List[ContainerRule] = \ + OrderlessField(default_factory=lambda: [ContainerRule(pattern="", strategy="any")]) umask: str = "0022" - user_idname: ContainerRule = field(default_factory=lambda: ContainerRule(pattern="", strategy="any")) + user_idname: ContainerRule = \ + Field(default_factory=lambda: ContainerRule(pattern="", strategy="any")) @dataclass @@ -69,7 +71,8 @@ class FragmentReference: feed: str issuer: str minimum_svn: str - includes: list[Literal["containers", "fragments", "namespace", "external_processes"]] + includes: List[Literal["containers", "fragments", "namespace", "external_processes"]] = \ + OrderlessField(default_factory=list) path: Optional[str] = None @@ -78,18 +81,18 @@ class FragmentReference: class Container: allow_elevated: bool = False allow_stdio_access: bool = True - capabilities: ContainerCapabilities = field(default_factory=ContainerCapabilities) - command: Optional[list[str]] = None - env_rules: list[ContainerRule] = field(default_factory=list) - exec_processes: list[ContainerExecProcesses] = field(default_factory=list) + capabilities: ContainerCapabilities = Field(default_factory=ContainerCapabilities) + command: Optional[List[str]] = None + env_rules: List[ContainerRule] = OrderlessField(default_factory=list) + exec_processes: List[ContainerExecProcesses] = OrderlessField(default_factory=list) id: Optional[str] = None - layers: list[str] = field(default_factory=list) - mounts: list[ContainerMount] = field(default_factory=list) + layers: List[str] = Field(default_factory=list) + mounts: List[ContainerMount] = OrderlessField(default_factory=list) name: Optional[str] = None no_new_privileges: bool = False seccomp_profile_sha256: str = "" - signals: list[str] = field(default_factory=list) - user: ContainerUser = field(default_factory=ContainerUser) + signals: List[str] = OrderlessField(default_factory=list) + user: ContainerUser = Field(default_factory=ContainerUser) working_dir: str = "/" @@ -99,8 +102,8 @@ class Policy: package: str = "policy" api_version: str = "0.10.0" framework_version: str = "0.2.3" - fragments: list[FragmentReference] = field(default_factory=list) - containers: list[Container] = field(default_factory=list) + fragments: List[FragmentReference] = OrderlessField(default_factory=list) + containers: List[Container] = OrderlessField(default_factory=list) allow_properties_access: bool = True allow_dump_stacks: bool = False allow_runtime_logging: bool = False @@ -114,5 +117,5 @@ class Fragment: package: str = "fragment" svn: str = "0" framework_version: str = "0.2.3" - fragments: list[FragmentReference] = field(default_factory=list) - containers: list[Container] = field(default_factory=list) + fragments: List[FragmentReference] = OrderlessField(default_factory=list) + containers: List[Container] = OrderlessField(default_factory=list) diff --git a/src/confcom/azext_confcom/lib/serialization.py b/src/confcom/azext_confcom/lib/serialization.py new file mode 100644 index 00000000000..4dcaab18bfe --- /dev/null +++ b/src/confcom/azext_confcom/lib/serialization.py @@ -0,0 +1,100 @@ + +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from dataclasses import asdict +import json +from pathlib import Path +from textwrap import dedent +from typing import Union + +from azext_confcom.lib.opa import opa_eval +from azext_confcom.lib.policy import Container, FragmentReference, Fragment, Policy +import re + + +# This is a single entrypoint for serializing both Policy and Fragment objects +def policy_serialize(policy: Union[Policy, Fragment]): + + if isinstance(policy, Fragment): + return fragment_serialize(policy) + + policy_dict = asdict(policy) + fragments_json = json.dumps(policy_dict.pop("fragments"), indent=2) + containers_json = json.dumps(policy_dict.pop("containers"), indent=2) + + return dedent(f""" +package {policy_dict.pop('package')} + +api_version := "{policy_dict.pop('api_version')}" +framework_version := "{policy_dict.pop('framework_version')}" + +fragments := {fragments_json} + +containers := {containers_json} + +{chr(10).join(f"{key} := {str(value).lower()}" for key, value in policy_dict.items() if key.startswith("allow"))} + +mount_device := data.framework.mount_device +unmount_device := data.framework.unmount_device +mount_overlay := data.framework.mount_overlay +unmount_overlay := data.framework.unmount_overlay +create_container := data.framework.create_container +exec_in_container := data.framework.exec_in_container +exec_external := data.framework.exec_external +shutdown_container := data.framework.shutdown_container +signal_container_process := data.framework.signal_container_process +plan9_mount := data.framework.plan9_mount +plan9_unmount := data.framework.plan9_unmount +get_properties := data.framework.get_properties +dump_stacks := data.framework.dump_stacks +runtime_logging := data.framework.runtime_logging +load_fragment := data.framework.load_fragment +scratch_mount := data.framework.scratch_mount +scratch_unmount := data.framework.scratch_unmount + +reason := {{"errors": data.framework.errors}} +""") + + +def fragment_serialize(fragment: Fragment): + + fragment_dict = asdict(fragment) + fragments_json = json.dumps(fragment_dict.pop("fragments"), indent=2) + containers_json = json.dumps(fragment_dict.pop("containers"), indent=2) + + return dedent(f""" +package {fragment_dict.pop('package')} + +svn := "{fragment_dict.pop('svn')}" +framework_version := "{fragment_dict.pop('framework_version')}" + +fragments := {fragments_json} + +containers := {containers_json} +""") + + +def policy_deserialize(file_path: str): + + with open(file_path, 'r') as f: + content = f.read() + + package_match = re.search(r'package\s+(\S+)', content) + package_name = package_match.group(1) + + PolicyType = Policy if package_name == "policy" else Fragment + + raw_json = opa_eval(Path(file_path), f"data.{package_name}")["result"][0]["expressions"][0]["value"] + + raw_fragments = raw_json.pop("fragments", []) + raw_containers = raw_json.pop("containers", []) + + return PolicyType( + package=package_name, + fragments=[FragmentReference(**fragment) for fragment in raw_fragments], + containers=[Container(**container) for container in raw_containers], + **raw_json + ) diff --git a/src/confcom/azext_confcom/security_policy.py b/src/confcom/azext_confcom/security_policy.py index 73219e21518..bbecbf528b2 100644 --- a/src/confcom/azext_confcom/security_policy.py +++ b/src/confcom/azext_confcom/security_policy.py @@ -4,11 +4,11 @@ # -------------------------------------------------------------------------------------------- import copy -from dataclasses import asdict import json import warnings from enum import Enum, auto from typing import Any, Dict, List, Optional, Tuple, Union +from pydantic import TypeAdapter import deepdiff from azext_confcom import config, os_util @@ -411,7 +411,10 @@ def _policy_serialization(self, pretty_print=False, include_sidecars: bool = Tru for container in policy: container[config.POLICY_FIELD_CONTAINERS_ELEMENTS_ALLOW_STDIO_ACCESS] = False - policy += [asdict(Container(**c)) for c in self._container_definitions] + policy += [ + TypeAdapter(Container).dump_python(Container(**c), mode="json") + for c in self._container_definitions + ] if pretty_print: return pretty_print_func(policy) diff --git a/src/confcom/azext_confcom/tests/latest/test_confcom_acipolicygen_arm.py b/src/confcom/azext_confcom/tests/latest/test_confcom_acipolicygen_arm.py index 991201ef6e3..255b67e8364 100644 --- a/src/confcom/azext_confcom/tests/latest/test_confcom_acipolicygen_arm.py +++ b/src/confcom/azext_confcom/tests/latest/test_confcom_acipolicygen_arm.py @@ -14,6 +14,8 @@ from itertools import product from azext_confcom.custom import acipolicygen_confcom +from azext_confcom.lib.serialization import policy_deserialize + TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), "..")) @@ -262,7 +264,7 @@ def test_acipolicygen_arm_diff_with_allow_all(): ['{"id": "test"}'], # Single container definition a field changed ] ) -def test_acipolicygen_with_containers(container_definitions): +def test_acipolicygen_with_containers_input_forms(container_definitions): acipolicygen_confcom( input_path=None, @@ -294,3 +296,54 @@ def test_acipolicygen_with_containers_field_changed(): ) actual_policy = buffer.getvalue() assert '"id":"test"' in actual_policy + + +@pytest.mark.parametrize( + "sample_directory", + os.listdir(SAMPLES_ROOT), +) +def test_acipolicygen_with_containers(sample_directory): + + # Load expected policy + with open(os.path.join(SAMPLES_ROOT, sample_directory, "policy.rego")) as expected_policy_file: + expected_policy_str = expected_policy_file.read() + + # Load input container definition + input_containers = [] + for file_path in os.listdir(os.path.join(SAMPLES_ROOT, sample_directory)): + if file_path.startswith("container"): + with open(os.path.join(SAMPLES_ROOT, sample_directory, file_path)) as input_containers_file: + input_containers.append(json.loads(input_containers_file.read())) + + # Generate a policy + buffer = io.StringIO() + with contextlib.redirect_stdout(buffer): + acipolicygen_confcom( + input_path=None, + arm_template=None, + arm_template_parameters=None, + image_name=None, + virtual_node_yaml_path=None, + infrastructure_svn=None, + tar_mapping_location=None, + outraw=True, + container_definitions=input_containers, + ) + actual_policy_str = buffer.getvalue() + + # Deserialize both policies for comparison (serialised policies might differ in formatting) + with tempfile.NamedTemporaryFile(mode="w+", delete=True) as actual_policy_file, \ + tempfile.NamedTemporaryFile(mode="w+", delete=True) as expected_policy_file: + + actual_policy_file.write(actual_policy_str) + actual_policy_file.flush() + actual_policy = policy_deserialize(actual_policy_file.name) + + for expected in [e for e in expected_policy_str.split("package policy") if e.strip()]: + expected_policy_file.seek(0) + expected_policy_file.truncate() + expected_policy_file.write(f"package policy{expected}") + expected_policy_file.flush() + expected_policy = policy_deserialize(expected_policy_file.name) + + assert actual_policy == expected_policy diff --git a/src/confcom/samples/aci/command/container1.rego b/src/confcom/samples/aci/command/container1.rego new file mode 100644 index 00000000000..58144f44e6f --- /dev/null +++ b/src/confcom/samples/aci/command/container1.rego @@ -0,0 +1,77 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1", + "command": ["/bin/sh","-c","while true; do echo hello; sleep 10; done"] +} \ No newline at end of file diff --git a/src/confcom/samples/aci/conflicting_variables/container1.rego b/src/confcom/samples/aci/conflicting_variables/container1.rego new file mode 100644 index 00000000000..07463aff04f --- /dev/null +++ b/src/confcom/samples/aci/conflicting_variables/container1.rego @@ -0,0 +1,92 @@ +{ + "command": [ + "python3", + "main.py" + ], + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "PYTHONUNBUFFERED=1", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/acc/samples/aci/helloworld@sha256:86da7a2c5e55b72bf6bc7cf465b860e49c075395d854877124de63a9342ac777", + "layers": [ + "4e74440c7b0e6e6c1cc9e6eb9b779e1ffde807122ed8a16bb0422a1d64fd5aa8", + "4cf856bcde8e1fa71f57d2218e21dd7c1a6a12c6d930d2bdb4bdb13a46fed9e4", + "41a52f45506177737caec5d57fe6160b6c8942dcac1bc7834fc0e94e62ff6b4d", + "b8ea8eae7795453b5e3dcfafe3f11fb2d68efb1062308e4d2411d44dd19fa97c", + "a0df1939f552483286c45204e7f583c9a6146963a79556fe22578d7b7e63e7a1", + "3ccbd6b119e951f3f2586339e9d10168b064a5852fd87cfae94af47a89f4d6c6", + "8348c9d4357db6a600aa4c5116ed9755a230d274096706a7d214c02105d0b256" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1", + "working_dir": "/app" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/container_group_profiles/container1.rego b/src/confcom/samples/aci/container_group_profiles/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/container_group_profiles/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/default_variables/container1.rego b/src/confcom/samples/aci/default_variables/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/default_variables/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/default_variables_override/container1.rego b/src/confcom/samples/aci/default_variables_override/container1.rego new file mode 100644 index 00000000000..07463aff04f --- /dev/null +++ b/src/confcom/samples/aci/default_variables_override/container1.rego @@ -0,0 +1,92 @@ +{ + "command": [ + "python3", + "main.py" + ], + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "PYTHONUNBUFFERED=1", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/acc/samples/aci/helloworld@sha256:86da7a2c5e55b72bf6bc7cf465b860e49c075395d854877124de63a9342ac777", + "layers": [ + "4e74440c7b0e6e6c1cc9e6eb9b779e1ffde807122ed8a16bb0422a1d64fd5aa8", + "4cf856bcde8e1fa71f57d2218e21dd7c1a6a12c6d930d2bdb4bdb13a46fed9e4", + "41a52f45506177737caec5d57fe6160b6c8942dcac1bc7834fc0e94e62ff6b4d", + "b8ea8eae7795453b5e3dcfafe3f11fb2d68efb1062308e4d2411d44dd19fa97c", + "a0df1939f552483286c45204e7f583c9a6146963a79556fe22578d7b7e63e7a1", + "3ccbd6b119e951f3f2586339e9d10168b064a5852fd87cfae94af47a89f4d6c6", + "8348c9d4357db6a600aa4c5116ed9755a230d274096706a7d214c02105d0b256" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1", + "working_dir": "/app" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/environment_variables/container1.rego b/src/confcom/samples/aci/environment_variables/container1.rego new file mode 100644 index 00000000000..50945502f96 --- /dev/null +++ b/src/confcom/samples/aci/environment_variables/container1.rego @@ -0,0 +1,81 @@ +{ + "env_rules": [ + { + "pattern": "MY_VAR=MY_VAL", + "required": false, + "strategy": "string" + }, + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/existing_policy/container1.rego b/src/confcom/samples/aci/existing_policy/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/existing_policy/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/existing_policy_allow_all/container1.rego b/src/confcom/samples/aci/existing_policy_allow_all/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/existing_policy_allow_all/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/minimal/container1.rego b/src/confcom/samples/aci/minimal/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/minimal/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/multi_container_groups/container1.rego b/src/confcom/samples/aci/multi_container_groups/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/multi_container_groups/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/multi_containers/container1.rego b/src/confcom/samples/aci/multi_containers/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/multi_containers/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/multi_containers/container2.rego b/src/confcom/samples/aci/multi_containers/container2.rego new file mode 100644 index 00000000000..2d57ce278c0 --- /dev/null +++ b/src/confcom/samples/aci/multi_containers/container2.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container2" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/security_context_capabilities_add/container1.rego b/src/confcom/samples/aci/security_context_capabilities_add/container1.rego new file mode 100644 index 00000000000..8159e6464fc --- /dev/null +++ b/src/confcom/samples/aci/security_context_capabilities_add/container1.rego @@ -0,0 +1,134 @@ +{ + "capabilities": { + "ambient": [], + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT", + "CAP_SYS_TIME" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT", + "CAP_SYS_TIME" + ], + "inheritable": [], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT", + "CAP_SYS_TIME" + ] + }, + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/security_context_capabilities_add_drop/container1.rego b/src/confcom/samples/aci/security_context_capabilities_add_drop/container1.rego new file mode 100644 index 00000000000..15877f7ebb8 --- /dev/null +++ b/src/confcom/samples/aci/security_context_capabilities_add_drop/container1.rego @@ -0,0 +1,128 @@ +{ + "capabilities": { + "ambient": [], + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT", + "CAP_SYS_TIME" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT", + "CAP_SYS_TIME" + ], + "inheritable": [], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT", + "CAP_SYS_TIME" + ] + }, + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/security_context_capabilities_drop/container1.rego b/src/confcom/samples/aci/security_context_capabilities_drop/container1.rego new file mode 100644 index 00000000000..570587214de --- /dev/null +++ b/src/confcom/samples/aci/security_context_capabilities_drop/container1.rego @@ -0,0 +1,122 @@ +{ + "capabilities": { + "ambient": [], + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_DAC_OVERRIDE", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_DAC_OVERRIDE", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT" + ], + "inheritable": [], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_DAC_OVERRIDE", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_MKNOD", + "CAP_NET_BIND_SERVICE", + "CAP_NET_RAW", + "CAP_SETFCAP", + "CAP_SETGID", + "CAP_SETPCAP", + "CAP_SETUID", + "CAP_SYS_CHROOT" + ] + }, + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/security_context_run_as_group/container1.rego b/src/confcom/samples/aci/security_context_run_as_group/container1.rego new file mode 100644 index 00000000000..33b07ea7ebf --- /dev/null +++ b/src/confcom/samples/aci/security_context_run_as_group/container1.rego @@ -0,0 +1,89 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1", + "user": { + "group_idnames": [ + { + "pattern": "4567", + "strategy": "id" + } + ], + "umask": "0022", + "user_idname": { + "pattern": "", + "strategy": "any" + } + } +} \ No newline at end of file diff --git a/src/confcom/samples/aci/security_context_run_as_user/container1.rego b/src/confcom/samples/aci/security_context_run_as_user/container1.rego new file mode 100644 index 00000000000..74c3cd5266d --- /dev/null +++ b/src/confcom/samples/aci/security_context_run_as_user/container1.rego @@ -0,0 +1,82 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1", + "user": { + "user_idname": { + "pattern": "1234", + "strategy": "id" + } + } +} \ No newline at end of file diff --git a/src/confcom/samples/aci/variables/container1.rego b/src/confcom/samples/aci/variables/container1.rego new file mode 100644 index 00000000000..1d1dfcf2dcc --- /dev/null +++ b/src/confcom/samples/aci/variables/container1.rego @@ -0,0 +1,76 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/volume_mount_secret/container1.rego b/src/confcom/samples/aci/volume_mount_secret/container1.rego new file mode 100644 index 00000000000..3a1aec238bf --- /dev/null +++ b/src/confcom/samples/aci/volume_mount_secret/container1.rego @@ -0,0 +1,86 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + }, + { + "destination": "/aci/secret", + "options": [ + "rbind", + "rshared", + "ro" + ], + "source": "sandbox:///tmp/atlas/secretsVolume/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/samples/aci/volume_mounts/container1.rego b/src/confcom/samples/aci/volume_mounts/container1.rego new file mode 100644 index 00000000000..a98fb6bdefd --- /dev/null +++ b/src/confcom/samples/aci/volume_mounts/container1.rego @@ -0,0 +1,86 @@ +{ + "env_rules": [ + { + "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "required": false, + "strategy": "string" + }, + { + "pattern": "TERM=xterm", + "required": false, + "strategy": "string" + }, + { + "pattern": "(?i)(FABRIC)_.+=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HOSTNAME=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "T(E)?MP=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "FabricPackageFileName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "HostedServiceName=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_API_VERSION=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_HEADER=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "IDENTITY_SERVER_THUMBPRINT=.+", + "required": false, + "strategy": "re2" + }, + { + "pattern": "azurecontainerinstance_restarted_by=.+", + "required": false, + "strategy": "re2" + } + ], + "id": "mcr.microsoft.com/azurelinux/distroless/base@sha256:1e77d97e1e39f22ed9c52f49b3508b4c1044cec23743df9098ac44e025f654f2", + "layers": [ + "243e1b3ce08093f2f0d9cd6a9eafde8737f64fec105ed59c346d309fbe760b58" + ], + "mounts": [ + { + "destination": "/etc/resolv.conf", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/resolvconf/.+", + "type": "bind" + }, + { + "destination": "/aci/logs", + "options": [ + "rbind", + "rshared", + "rw" + ], + "source": "sandbox:///tmp/atlas/azureFileVolume/.+", + "type": "bind" + } + ], + "name": "container1" +} \ No newline at end of file diff --git a/src/confcom/setup.py b/src/confcom/setup.py index 359b1f80654..a2fc01aef63 100644 --- a/src/confcom/setup.py +++ b/src/confcom/setup.py @@ -11,6 +11,7 @@ from azext_confcom.rootfs_proxy import SecurityPolicyProxy from azext_confcom.kata_proxy import KataPolicyGenProxy from azext_confcom.cose_proxy import CoseSignToolProxy +from azext_confcom.lib.opa import opa_get try: from azure_bdist_wheel import cmdclass @@ -19,7 +20,7 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") -VERSION = "1.4.1" +VERSION = "1.4.2" # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers @@ -41,12 +42,14 @@ "docker>=6.1.0", "tqdm==4.65.0", "deepdiff~=8.6.1", - "PyYAML>=6.0.1" + "PyYAML>=6.0.1", + "pydantic>=2.12.4", ] SecurityPolicyProxy.download_binaries() KataPolicyGenProxy.download_binaries() CoseSignToolProxy.download_binaries() +opa_get() with open("README.md", "r", encoding="utf-8") as f: README = f.read()