Skip to content
Merged
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
5 changes: 5 additions & 0 deletions src/confcom/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Release History
===============
0.2.16
* adding stop signals as a field that is picked up from image manifest and placed into policy
* updating --print-existing-policy to print the whole policy
* refactoring tests to be more portable across releases

0.2.15
* updating dmverity-vhd interface to be more flexible with output formats
* bugfix for --print-existing-policy flag with parameter values
Expand Down
36 changes: 36 additions & 0 deletions src/confcom/azext_confcom/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,39 @@
DEFAULT_UNPRIVILEGED_CAPABILITIES = _config["default_unprivileged_capabilities"]
# default priviliged user capabilities to be added for security context
DEFAULT_PRIVILEGED_CAPABILITIES = _config["default_privileged_capabilities"]
# these signals are hardcoded because the signals package in python is not portable across platforms
SIGNALS = {
"SIGHUP": 1,
"SIGINT": 2,
"SIGQUIT": 3,
"SIGILL": 4,
"SIGTRAP": 5,
"SIGABRT": 6,
"SIGIOT": 6,
"SIGBUS": 7,
"SIGFPE": 8,
"SIGKILL": 9,
"SIGUSR1": 10,
"SIGSEGV": 11,
"SIGUSR2": 12,
"SIGPIPE": 13,
"SIGALRM": 14,
"SIGTERM": 15,
"SIGSTKFLT": 16,
"SIGCHLD": 17,
"SIGCONT": 18,
"SIGSTOP": 19,
"SIGTSTP": 20,
"SIGTTIN": 21,
"SIGTTOU": 22,
"SIGURG": 23,
"SIGXCPU": 24,
"SIGXFSZ": 25,
"SIGVTALRM": 26,
"SIGPROF": 27,
"SIGWINCH": 28,
"SIGIO": 29,
"SIGPWR": 30,
"SIGSYS": 31,
"SIGUNUSED": 31
}
8 changes: 7 additions & 1 deletion src/confcom/azext_confcom/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
case_insensitive_dict_get,
replace_params_and_vars,
str_to_sha256,
process_seccomp_policy
process_seccomp_policy,
translate_signals
)
from azext_confcom import config
from azext_confcom.errors import eprint
Expand Down Expand Up @@ -575,6 +576,10 @@ def get_id(self) -> str:
def get_working_dir(self) -> str:
return self._workingDir

def set_signals(self, signals: List) -> None:
signals = translate_signals([signals] if not isinstance(signals, list) else signals)
self._signals = signals

def set_working_dir(self, workingDir: str) -> None:
self._workingDir = workingDir

Expand Down Expand Up @@ -688,6 +693,7 @@ def _get_mounts_json(self) -> Dict[str, Any]:
return mounts

def _populate_policy_json_elements(self) -> Dict[str, Any]:

elements = {
config.POLICY_FIELD_CONTAINERS_ID: self._identifier,
config.POLICY_FIELD_CONTAINERS_ELEMENTS_LAYERS: self._layers,
Expand Down
2 changes: 1 addition & 1 deletion src/confcom/azext_confcom/data/internal_config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.2.15",
"version": "0.2.16",
"hcsshim_config": {
"maxVersion": "1.0.0",
"minVersion": "0.0.1"
Expand Down
6 changes: 6 additions & 0 deletions src/confcom/azext_confcom/security_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ def _policy_serialization(self, pretty_print=False) -> str:
return pretty_print_func(policy)
return print_func(policy)

# pylint: disable=R0914, R0915
Comment thread
hgarvison marked this conversation as resolved.
def populate_policy_content_for_all_images(
self, individual_image=False, tar_mapping=None
) -> None:
Expand Down Expand Up @@ -432,6 +433,11 @@ def populate_policy_content_for_all_images(
}
)

# merge signals for user container image
signals = image_info.get("StopSignal")
if signals:
image.set_signals(signals)

if (deepdiff.DeepDiff(image.get_user(), config.DEFAULT_USER, ignore_order=True) == {}
and image_info.get("User") != ""):
# valid values are in the form "user", "user:group", "uid", "uid:gid", "user:gid", "uid:group"
Expand Down
7 changes: 7 additions & 0 deletions src/confcom/azext_confcom/template_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,13 @@ def is_sidecar(image_name: str) -> bool:
return image_name.split(":")[0] in config.BASELINE_SIDECAR_CONTAINERS


def translate_signals(signals: List[str]) -> List[int]:
for i, signal_val in enumerate(signals):
if isinstance(signal_val, str) and signal_val.upper() in config.SIGNALS:
signals[i] = config.SIGNALS[signal_val.upper()]
return signals


def compare_env_vars(
id_val, env_list1: List[Dict[str, Any]], env_list2: List[Dict[str, Any]]
) -> Dict[str, List[str]]:
Expand Down
140 changes: 139 additions & 1 deletion src/confcom/azext_confcom/tests/latest/test_confcom_arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5302,4 +5302,142 @@ def test_arm_template_security_context_seccomp_profile_missing_syscalls(self):
)
)

self.assertEqual(regular_image_json[0][config.POLICY_FIELD_CONTAINERS_ELEMENTS_SECCOMP_PROFILE_SHA256], expected_seccomp_profile_sha256)
self.assertEqual(regular_image_json[0][config.POLICY_FIELD_CONTAINERS_ELEMENTS_SECCOMP_PROFILE_SHA256], expected_seccomp_profile_sha256)


# @unittest.skip("not in use")
@pytest.mark.run(order=18)
class PolicyStopSignal(unittest.TestCase):
custom_arm_json = """
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"variables": {
"image": "nginx:1.24"
},


"parameters": {
"containergroupname": {
"type": "string",
"metadata": {
"description": "Name for the container group"
},
"defaultValue":"simple-container-group"
},

"containername": {
"type": "string",
"metadata": {
"description": "Name for the container"
},
"defaultValue":"simple-container"
},
"port": {
"type": "string",
"metadata": {
"description": "Port to open on the container and the public IP address."
},
"defaultValue": "80"
},
"cpuCores": {
"type": "string",
"metadata": {
"description": "The number of CPU cores to allocate to the container."
},
"defaultValue": "1.0"
},
"memoryInGb": {
"type": "string",
"metadata": {
"description": "The amount of memory to allocate to the container in gigabytes."
},
"defaultValue": "1.5"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"resources": [
{
"name": "[parameters('containergroupname')]",
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2022-04-01-preview",
"location": "[parameters('location')]",
"properties": {
"containers": [
{
"name": "[parameters('containername')]",

"properties": {
"image": "[variables('image')]",
"command": [
"python3"
],
"ports": [
{
"port": "[parameters('port')]"
}
],
"resources": {
"requests": {
"cpu": "[parameters('cpuCores')]",
"memoryInGb": "[parameters('memoryInGb')]"
}
}

}
}

],

"osType": "Linux",
"restartPolicy": "OnFailure",
"confidentialComputeProperties": {
"IsolationType": "SevSnp"
},
"ipAddress": {
"type": "Public",
"ports": [
{
"protocol": "Tcp",
"port": "[parameters( 'port' )]"
}
]
}
}
}
],
"outputs": {
"containerIPv4Address": {
"type": "string",
"value": "[reference(resourceId('Microsoft.ContainerInstance/containerGroups/', parameters('containergroupname'))).ipAddress.ip]"
}
}
}
"""
aci_policy = None

@classmethod
def setUpClass(cls):

cls.aci_arm_policy = load_policy_from_arm_template_str(cls.custom_arm_json, "")[
0
]
cls.aci_arm_policy.populate_policy_content_for_all_images()

def test_stop_signal(self):
regular_image_json = json.loads(
self.aci_arm_policy.get_serialized_output(
output_type=OutputType.RAW, rego_boilerplate=False
)
)
# check for the signal for SIGQUIT. this is part of the nginx image
self.assertTrue(
3 in
Comment thread
hgarvison marked this conversation as resolved.
regular_image_json[0][config.POLICY_FIELD_CONTAINERS_ELEMENTS_SIGNAL_CONTAINER_PROCESSES]
)
2 changes: 1 addition & 1 deletion src/confcom/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

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

VERSION = "0.2.15"
VERSION = "0.2.16"

# The full list of classifiers is available at
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
Expand Down