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
2 changes: 2 additions & 0 deletions src/confcom/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ azext_confcom/bin/*
**/.coverage

**/htmlcov

!lib/
11 changes: 8 additions & 3 deletions src/confcom/azext_confcom/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,12 +791,17 @@ def from_json(
) -> "UserContainerImage":
image = super().from_json(container_json)
image.__class__ = UserContainerImage
mount_paths = {m["mountPath"] for m in image.get_mounts()}
# inject default mounts for user container
if (image.base not in config.BASELINE_SIDECAR_CONTAINERS) and (not is_vn2):
image.get_mounts().extend(_DEFAULT_MOUNTS)
if image.base not in config.BASELINE_SIDECAR_CONTAINERS and not is_vn2:
for mount in _DEFAULT_MOUNTS:
if mount["mountPath"] not in mount_paths:
image.get_mounts().append(mount)

if (image.base not in config.BASELINE_SIDECAR_CONTAINERS) and (is_vn2):
image.get_mounts().extend(_DEFAULT_MOUNTS_VN2)
for mount in _DEFAULT_MOUNTS_VN2:
if mount["mountPath"] not in mount_paths:
image.get_mounts().append(mount)

# Start with the customer environment rules
env_rules = copy.deepcopy(_INJECTED_CUSTOMER_ENV_RULES)
Expand Down
28 changes: 22 additions & 6 deletions src/confcom/azext_confcom/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import json
import os
import sys

Expand All @@ -17,7 +18,7 @@
from azext_confcom.kata_proxy import KataPolicyGenProxy
from azext_confcom.security_policy import OutputType
from azext_confcom.template_util import (
get_image_name, inject_policy_into_template, inject_policy_into_yaml,
extract_confidential_properties, get_image_name, inject_policy_into_template, inject_policy_into_yaml,
pretty_print_func, print_existing_policy_from_arm_template,
print_existing_policy_from_yaml, print_func, str_to_sha256)
from knack.log import get_logger
Expand Down Expand Up @@ -123,8 +124,7 @@ def acipolicygen_confcom(
debug_mode=debug_mode,
disable_stdio=disable_stdio,
approve_wildcards=approve_wildcards,
diff_mode=diff,
rego_imports=fragments_list,
included_fragments=fragments_list,
exclude_default_fragments=exclude_default_fragments,
)
elif image_name:
Expand Down Expand Up @@ -168,7 +168,23 @@ def acipolicygen_confcom(
for policy in container_group_policies:
policy.set_fragment_contents(fragment_policy_list)

for count, policy in enumerate(container_group_policies):
for idx, policy in enumerate(container_group_policies):

# We will deprecate diff mode in favour of a separate tool, so we want
# supporting code to be all in one place even if it makes it more nasty
if diff:
if arm_template:
with open(arm_template, 'r') as f:
# pylint: disable=protected-access
policy._existing_cce_policy = extract_confidential_properties(
[r for r in json.load(f)["resources"] if r["type"] in {
"Microsoft.ContainerInstance/containerGroups",
"Microsoft.ContainerInstance/containerGroupProfiles",
}][idx].get("properties", {}))[0]

elif virtual_node_yaml_path:
... # diff mode is handled in the load function

# this is where parameters and variables are populated
policy.populate_policy_content_for_all_images(
individual_image=bool(image_name), tar_mapping=tar_mapping, faster_hashing=faster_hashing
Expand All @@ -178,7 +194,7 @@ def acipolicygen_confcom(
exit_code = validate_sidecar_in_policy(policy, output_type == security_policy.OutputType.PRETTY_PRINT)
elif virtual_node_yaml_path and not (print_policy_to_terminal or outraw or outraw_pretty_print or diff):
result = inject_policy_into_yaml(
virtual_node_yaml_path, policy.get_serialized_output(omit_id=omit_id), count
virtual_node_yaml_path, policy.get_serialized_output(omit_id=omit_id), idx
)
if result:
print(str_to_sha256(policy.get_serialized_output(OutputType.RAW, omit_id=omit_id)))
Expand All @@ -187,7 +203,7 @@ def acipolicygen_confcom(
exit_code = get_diff_outputs(policy, output_type == security_policy.OutputType.PRETTY_PRINT)
elif arm_template and not (print_policy_to_terminal or outraw or outraw_pretty_print):
result = inject_policy_into_template(arm_template, arm_template_parameters,
policy.get_serialized_output(omit_id=omit_id), count)
policy.get_serialized_output(omit_id=omit_id), idx)
if result:
# this is always going to be the unencoded policy
print(str_to_sha256(policy.get_serialized_output(OutputType.RAW, omit_id=omit_id)))
Expand Down
84 changes: 84 additions & 0 deletions src/confcom/azext_confcom/lib/aci_policy_spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# --------------------------------------------------------------------------------------------
# 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 dataclass
from typing import Optional
from typing_extensions import Literal


@dataclass
class AciContainerPropertyEnvVariable:
name: str
value: str
strategy: str
required: Optional[bool] = False


@dataclass
class AciContainerPropertyExecProcesses:
command: list[str]
signals: Optional[list[str]] = None
allow_stdio_access: bool = True


@dataclass
class AciContainerPropertyVolumeMounts:
mountPath: str
name: Optional[str] = None
readonly: bool = False
mountType: Optional[Literal["azureFile", "secret", "configMap", "emptyDir"]] = None


@dataclass
class AciContainerPropertySecurityContextCapabilities:
add: list[str]
drop: list[str]


@dataclass
class AciContainerPropertySecurityContext:
privileged: Optional[bool] = None
allowPrivilegeEscalation: Optional[bool] = None
runAsUser: Optional[int] = None
runAsGroup: Optional[int] = None
runAsNonRoot: Optional[bool] = None
readOnlyRootFilesystem: Optional[bool] = None
capabilities: Optional[AciContainerPropertySecurityContextCapabilities] = None
seccompProfile: Optional[str] = None


@dataclass
class AciContainerProperties():
image: str
allowStdioAccess: bool = True
environmentVariables: Optional[list[AciContainerPropertyEnvVariable]] = None
execProcesses: Optional[list[AciContainerPropertyExecProcesses]] = None
volumeMounts: Optional[list[AciContainerPropertyVolumeMounts]] = None
securityContext: Optional[AciContainerPropertySecurityContext] = None
command: Optional[list[str]] = None


# ------------------------------------------------------------------------------


@dataclass
class AciFragmentSpec:
feed: str
issuer: str
minimum_svn: str
includes: list[Literal["containers", "fragments"]]
path: Optional[str] = None


@dataclass
class AciContainerSpec:
name: str
properties: AciContainerProperties


@dataclass
class AciPolicySpec:
fragments: Optional[list[AciFragmentSpec]]
containers: Optional[list[AciContainerSpec]]
Loading
Loading