Skip to content
Draft
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
18 changes: 18 additions & 0 deletions linter_exclusions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3504,3 +3504,21 @@ neon postgres organization:
neon postgres project:
rule_exclusions:
- require_wait_command_if_no_wait

confcom fragment push:
parameters:
signed_fragment:
rule_exclusions:
- no_positional_parameters

confcom fragment attach:
parameters:
signed_fragment:
rule_exclusions:
- no_positional_parameters

confcom policy containers set layers:
parameters:
policy_file:
rule_exclusions:
- no_positional_parameters
6 changes: 6 additions & 0 deletions src/confcom/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
Release History
===============

1.5.0
++++++
* restored the behaviour of --upload-fragment in acifragmentgen to attach to first image in input
* added confcom fragment push command to allow explicit uploading of standalone fragments
* added confcom fragment attach command to allow explicit uploading of image attached fragments

1.4.5
++++++
* Drop the dependency on OPA
Expand Down
94 changes: 94 additions & 0 deletions src/confcom/azext_confcom/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,97 @@
- name: Input a Kubernetes YAML file with a custom containerd socket path
text: az confcom katapolicygen --yaml "./pod.json" --containerd-pull --containerd-socket-path "/my/custom/containerd.sock"
"""

helps[
"confcom fragment"
] = """
type: group
short-summary: Commands to handle Confidential Container Policy Fragments.
"""

helps[
"confcom fragment push"
] = """
type: command
short-summary: Push a Confidential Container Policy Fragment to an ORAS registry

parameters:
- name: --manifest-tag
type: string
short-summary: 'The reference to push the signed fragment to'

examples:
- name: Push a signed fragment to a registry
text: az confcom fragment push ./fragment.reg.cose --manifest-tag myregistry.azurecr.io/fragment:latest
- name: Push the output of acifragmentgen to a registry
text: az confcom acifragmentgen --chain my.cert.pem --key my_key.pem --svn "1" --namespace contoso --feed "test-feed" --input ./fragment_spec.json | az confcom fragment push --manifest-tag myregistry.azurecr.io/fragment:latest
"""

helps[
"confcom fragment attach"
] = """
type: command
short-summary: Attach a Confidential Container Policy Fragment to an image in an ORAS registry.

parameters:
- name: --manifest-tag
type: string
short-summary: 'The reference to attach the signed fragment to'

examples:
- name: Attach a signed fragment to a registry
text: az confcom fragment attach ./fragment.reg.cose --manifest-tag myregistry.azurecr.io/image:latest
- name: Attach the output of acifragmentgen to a registry
text: az confcom acifragmentgen --chain my.cert.pem --key my_key.pem --svn "1" --namespace contoso --feed "test-feed" --input ./fragment_spec.json | az confcom fragment attach --manifest-tag myregistry.azurecr.io/image:latest
"""

helps[
"confcom policy"
] = """
type: group
short-summary: Commands which operate on Security Policies.
"""


helps[
"confcom policy containers"
] = """
type: group
short-summary: Commands which operate on the container definitions in Security Policies.
"""


helps[
"confcom policy containers set"
] = """
type: group
short-summary: Commands which set fields on the container definitions in Security Policies.
"""


helps[
"confcom policy containers set layers"
] = """
type: command
short-summary: Set the layers field of the specified container in a Security Policy.

parameters:
- name: --id
type: string
short-summary: 'The ID of the container definition to set the layers for'

- name: --image
type: string
short-summary: 'The image reference to derive the new layers from'

- name: --in-place -i
type: boolean
short-summary: 'When enabled, edit the policy in place, otherwise print the modified policy to stdout'


examples:
- name: Set the layers field of a container in a Security Policy
text: az confcom policy containers set layers --id my-container --image my-image:latest
- name: Set the layers field of a container in a Security Policy in place
text: az confcom policy containers set layers --id my-container --image my-image:latest -i
"""
63 changes: 63 additions & 0 deletions src/confcom/azext_confcom/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long

import argparse
import json
import sys
from knack.arguments import CLIArgumentType
from azext_confcom._validators import (
validate_params_file,
Expand Down Expand Up @@ -44,6 +46,32 @@ def load_arguments(self, _):
c.argument("tags", tags_type)
c.argument("confcom_name", confcom_name_type, options_list=["--name", "-n"])

with self.argument_context("confcom fragment attach") as c:
c.positional(
"signed_fragment",
nargs='?',
type=argparse.FileType('rb'),
default=sys.stdin.buffer,
help="Signed fragment to attach",
)
c.argument(
"manifest_tag",
help="Manifest tag for the fragment",
)

with self.argument_context("confcom fragment push") as c:
c.positional(
"signed_fragment",
nargs='?',
type=argparse.FileType('rb'),
default=sys.stdin.buffer,
help="Signed fragment to push",
)
c.argument(
"manifest_tag",
help="Manifest tag for the fragment",
)

with self.argument_context("confcom acipolicygen") as c:
c.argument(
"input_path",
Expand Down Expand Up @@ -362,6 +390,13 @@ def load_arguments(self, _):
type=json.loads,
help='Container definitions to include in the policy'
)
c.argument(
"out_signed_fragment",
action="store_true",
default=False,
required=False,
help="Emit only the signed fragment bytes",
)

with self.argument_context("confcom katapolicygen") as c:
c.argument(
Expand Down Expand Up @@ -434,3 +469,31 @@ def load_arguments(self, _):
help="Path to containerd socket if not using the default",
validator=validate_katapolicygen_input,
)

with self.argument_context("confcom policy containers set layers") as c:
c.positional(
"policy_file",
nargs='?',
type=argparse.FileType('rb'),
default=sys.stdin.buffer,
help="Policy to add the container to",
)
c.argument(
"container_id",
options_list=("--id"),
help="Container ID to set layers for"
)
c.argument(
"image",
options_list=("--image"),
default=None,
help="Image to get the layers of"
)
c.argument(
"in_place",
options_list=("--in-place", "-i"),
action="store_true",
required=False,
default=False,
help="Edit the input file in place instead of outputting to stdout"
)
46 changes: 46 additions & 0 deletions src/confcom/azext_confcom/command/fragment_attach.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import os
import subprocess
import tempfile
from typing import BinaryIO


def oras_attach(
signed_fragment: BinaryIO,
manifest_tag: str,
) -> None:
subprocess.run(
[
"oras",
"attach",
"--artifact-type", "application/x-ms-ccepolicy-frag",
manifest_tag,
os.path.relpath(signed_fragment.name, start=os.getcwd()),
],
check=True,
timeout=120,
)


def fragment_attach(
signed_fragment: BinaryIO,
manifest_tag: str,
) -> None:

if signed_fragment.name == "<stdin>":
with tempfile.NamedTemporaryFile(delete=True) as temp_signed_fragment:
temp_signed_fragment.write(signed_fragment.read())
temp_signed_fragment.flush()
oras_attach(
signed_fragment=temp_signed_fragment,
manifest_tag=manifest_tag,
)
else:
oras_attach(
signed_fragment=signed_fragment,
manifest_tag=manifest_tag,
)
46 changes: 46 additions & 0 deletions src/confcom/azext_confcom/command/fragment_push.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import os
import subprocess
import tempfile
from typing import BinaryIO


def oras_push(
signed_fragment: BinaryIO,
manifest_tag: str,
) -> None:
subprocess.run(
[
"oras",
"push",
"--artifact-type", "application/x-ms-ccepolicy-frag",
manifest_tag,
os.path.relpath(signed_fragment.name, start=os.getcwd()),
],
check=True,
timeout=120,
)


def fragment_push(
signed_fragment: BinaryIO,
manifest_tag: str,
) -> None:

if signed_fragment.name == "<stdin>":
with tempfile.NamedTemporaryFile(delete=True) as temp_signed_fragment:
temp_signed_fragment.write(signed_fragment.read())
temp_signed_fragment.flush()
oras_push(
signed_fragment=temp_signed_fragment,
manifest_tag=manifest_tag,
)
else:
oras_push(
signed_fragment=signed_fragment,
manifest_tag=manifest_tag,
)
37 changes: 37 additions & 0 deletions src/confcom/azext_confcom/command/policy_containers_set_layers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import tempfile
from typing import BinaryIO, Optional
from azext_confcom.lib.serialization import policy_deserialize, policy_serialize
from azext_confcom.lib.images import get_image_layers


def policy_containers_set_layers(
policy_file: BinaryIO,
container_id: str,
image: Optional[str],
in_place: bool,
) -> str:

policy = None
if policy_file.name == "<stdin>":
assert not in_place
with tempfile.NamedTemporaryFile(delete=True) as temp_policy_file:
temp_policy_file.write(policy_file.read())
temp_policy_file.flush()
policy = policy_deserialize(temp_policy_file.name)
else:
policy = policy_deserialize(policy_file.name)

container = next(c for c in policy.containers if c.id == container_id)
container.layers = get_image_layers(image or container_id)
serialized_policy = policy_serialize(policy)

if in_place:
with open(policy_file.name, "w") as f:
f.write(serialized_policy)

return serialized_policy
7 changes: 7 additions & 0 deletions src/confcom/azext_confcom/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,12 @@ def load_command_table(self, _):
g.custom_command("acifragmentgen", "acifragmentgen_confcom")
g.custom_command("katapolicygen", "katapolicygen_confcom")

with self.command_group("confcom fragment") as g:
g.custom_command("attach", "fragment_attach", is_preview=True)
g.custom_command("push", "fragment_push", is_preview=True)

with self.command_group("confcom"):
pass

with self.command_group("confcom policy containers set") as g:
g.custom_command("layers", "policy_containers_set_layers")
Loading
Loading