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
4 changes: 4 additions & 0 deletions src/k8s-configuration/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Release History
===============
2.3.0
++++++++++++++++++
* Added support for using OCIRepository as a source type in Flux configurations.

2.2.0
++++++++++++++++++
* Introduce a new feature to add provider authentication for git repositories.
Expand Down
12 changes: 12 additions & 0 deletions src/k8s-configuration/azext_k8s_configuration/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
--kind azblob --url https://mystorageaccount.blob.core.windows.net \\
--container-name my-container --kustomization name=my-kustomization \\
--account-key my-account-key
- name: Create a Kubernetes v2 Flux Configuration with OCI Source Kind
text: |-
az k8s-configuration flux create --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters \\
--name myconfig --scope cluster --namespace my-namespace \\
--kind oci --url oci://ghcr.io/owner/repo/manifests/podinfo \\
--kustomization name=my-kustomization --use-workload-identity
"""

helps[
Expand All @@ -109,6 +116,11 @@
az k8s-configuration flux update --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters --name myconfig \\
--container-name other-container
- name: Update a Flux v2 Kubernetes configuration with OCI Source Kind to use connect insecurely
text: |-
az k8s-configuration flux update --resource-group my-resource-group \\
--cluster-name mycluster --cluster-type connectedClusters --name myconfig \\
--oci-insecure
"""

helps[
Expand Down
81 changes: 76 additions & 5 deletions src/k8s-configuration/azext_k8s_configuration/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from .action import (
KustomizationAddAction,
VerifyConfigAction
)
from . import consts

Expand Down Expand Up @@ -65,7 +66,7 @@ def load_arguments(self, _):
)
c.argument(
"kind",
arg_type=get_enum_type([consts.GIT, consts.BUCKET, consts.AZBLOB]),
arg_type=get_enum_type([consts.GIT, consts.BUCKET, consts.AZBLOB, consts.OCI]),
help="Source kind to reconcile",
)
c.argument(
Expand All @@ -86,13 +87,13 @@ def load_arguments(self, _):
)
c.argument(
"tag",
arg_group="Git Repo Ref",
help="Tag within the git source to reconcile with the cluster",
arg_group="Git Repo Ref / OCI Repo Ref",
help="Tag within the git or OCI source to reconcile with the cluster",
)
c.argument(
"semver",
arg_group="Git Repo Ref",
help="Semver range within the git source to reconcile with the cluster",
arg_group="Git Repo Ref / OCI Repo Ref",
help="Semver range within the git or OCI source to reconcile with the cluster",
)
c.argument(
"commit",
Expand Down Expand Up @@ -238,6 +239,76 @@ def load_arguments(self, _):
options_list=["--mi-client-id", "--managed-identity-client-id"],
help="The client ID of the managed identity for authentication with Azure Blob",
)
c.argument(
"digest",
arg_group="OCI Repo Ref",
help="Digest of the OCI artifact to reconcile with the cluster",
)
c.argument(
"oci_media_type",
arg_group="OCI Repo Ref",
options_list=["--oci-media-type", "--oci-layer-selector-media-type"],
help="OCI artifact layer media type to select for extraction or copy.",
)
c.argument(
"oci_operation",
arg_group="OCI Repo Ref",
arg_type=get_enum_type(["extract", "copy"]),
options_list=["--oci-operation", "--oci-layer-selector-operation"],
help="Operation to perform on the selected OCI artifact layer: 'extract' to extract the layer, 'copy' to copy the tarball as-is (default: extract)",
)
c.argument(
"tls_ca_certificate",
arg_group="OCI Repository Auth",
help="Base64-encoded CA certificate for TLS communication with OCI repository",
)
c.argument(
"tls_client_certificate",
arg_group="OCI Repository Auth",
help="Base64-encoded client certificate for TLS authentication with OCI repository",
)
c.argument(
"tls_private_key",
arg_group="OCI Repository Auth",
help="Base64-encoded private key for TLS authentication with OCI repository",
)
c.argument(
"service_account_name",
arg_group="OCI Repository Auth",
help="Name of the Kubernetes service account to use for accessing the OCI repository",
)
c.argument(
"use_workload_identity",
arg_group="OCI Repository Auth",
arg_type=get_three_state_flag(),
help="Use workload identity for authentication with OCI repository",
)
c.argument(
"oci_insecure",
arg_type=get_three_state_flag(),
help="Allow connecting to an insecure (HTTP) OCI container registry.",
)
c.argument(
"verification_provider",
action=VerifyConfigAction,
arg_group="OCI Repository Auth",
help="Provider used for OCI verification."
)
c.argument(
"match_oidc_identity",
action=VerifyConfigAction,
arg_group="OCI Repository Auth",
nargs="+",
help="List of OIDC identities to match for verification of OCI artifacts. Each entry should be a JSON string with 'issuer' and 'subject' fields."
)
c.argument(
"verification_config",
action=VerifyConfigAction,
arg_group="OCI Repository Auth",
nargs="+",
help="An object containing trusted public keys of trusted authors for OCI artifacts."
)


with self.argument_context("k8s-configuration flux update") as c:
c.argument(
Expand Down
39 changes: 39 additions & 0 deletions src/k8s-configuration/azext_k8s_configuration/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# pylint: disable=protected-access

import argparse
import json
from azure.cli.core.azclierror import InvalidArgumentValueError
from .vendored_sdks.v2024_04_01_preview.models import (
KustomizationDefinition,
Expand Down Expand Up @@ -75,3 +76,41 @@ def __call__(self, parser, namespace, values, option_string=None):
),
option_string,
)


class VerifyConfigAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
# Handle verification_provider (simple string)
if self.dest == "verification_provider":
setattr(namespace, self.dest, values)
return

# Handle match_oidc_identity (list of JSON strings)
if self.dest == "match_oidc_identity":
identities = []
for entry in values:
try:
obj = json.loads(entry)
if not isinstance(obj, dict) or "issuer" not in obj or "subject" not in obj:
raise ValueError()
identities.append({"issuer": obj["issuer"], "subject": obj["subject"]})
except Exception:
raise InvalidArgumentValueError(
"Each entry for --match-oidc-identity must be a JSON string with 'issuer' and 'subject' fields."
)
setattr(namespace, self.dest, identities)
return

# Handle verification_config (list of key=value)
if self.dest == "verification_config":
config = {}
for item in values:
try:
key, value = item.split("=", 1)
config[key] = value
except Exception:
raise InvalidArgumentValueError(
"Each entry for --verification-config must be in key=value format."
)
setattr(namespace, self.dest, config)
return
25 changes: 25 additions & 0 deletions src/k8s-configuration/azext_k8s_configuration/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,28 @@
"mi_client_id",
}

OCI_REPO_REQUIRED_PARAMS = {"url"}
OCI_REPO_VALID_PARAMS = {
"url",
"tag",
"semver",
"digest",
"sync_interval",
"timeout",
"local_auth_ref",
"oci_media_type",
"oci_operation",
"tls_ca_certificate",
"tls_client_certificate",
"tls_private_key",
"service_account_name",
"use_workload_identity",
"oci_insecure",
"verification_provider",
"match_oidc_identity",
"verification_config",
}

DEPENDENCY_KEYS = ["dependencies", "depends_on", "dependsOn", "depends"]
SYNC_INTERVAL_KEYS = ["interval", "sync_interval", "syncInterval"]
RETRY_INTERVAL_KEYS = ["retryInterval", "retry_interval"]
Expand All @@ -266,6 +288,7 @@
VALID_GIT_URL_REGEX = r"^(((http|https|ssh)://)|(git@))"
VALID_BUCKET_URL_REGEX = r"^(((http|https)://))"
VALID_AZUREBLOB_URL_REGEX = r"^(((http|https)://))"
VALID_OCI_URL_REGEX = r"^oci://.*$"

VALID_KUBERNETES_DNS_SUBDOMAIN_NAME_REGEX = r"^[a-z0-9]([\.\-a-z0-9]*[a-z0-9])?$"
VALID_KUBERNETES_DNS_NAME_REGEX = r"^[a-z0-9]([\-a-z0-9]*[a-z0-9])?$"
Expand All @@ -274,8 +297,10 @@
BUCKET = "bucket"
BUCKET_CAPS = "Bucket"
AZBLOB = "azblob"
OCI = "oci"
AZURE_BLOB = "AzureBlob"
GIT_REPOSITORY = "GitRepository"
OCI_REPOSITORY = "OCIRepository"

CONNECTED_CLUSTER_TYPE = "connectedclusters"
MANAGED_CLUSTER_TYPE = "managedclusters"
Expand Down
Loading
Loading