Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/u/mpiano/SEC-18955_poc'
Browse files Browse the repository at this point in the history
  • Loading branch information
piax93 committed May 14, 2024
2 parents 0fdbdcd + a483351 commit b2288ae
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 0 deletions.
22 changes: 22 additions & 0 deletions paasta_tools/cli/schemas/kubernetes_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,28 @@
},
"uniqueItems": true
},
"projected_sa_volumes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"container_path": {
"type": "string"
},
"audience": {
"type": "string"
},
"expiration_seconds": {
"type": "integer"
}
},
"required": [
"container_path",
"audience"
]
},
"uniqueItems": true
},
"replication_threshold": {
"type": "integer",
"minimum": 0
Expand Down
22 changes: 22 additions & 0 deletions paasta_tools/cli/schemas/tron_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,28 @@
},
"uniqueItems": true
},
"projected_sa_volumes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"container_path": {
"type": "string"
},
"audience": {
"type": "string"
},
"expiration_seconds": {
"type": "integer"
}
},
"required": [
"container_path",
"audience"
]
},
"uniqueItems": true
},
"cluster": {
"type": "string"
},
Expand Down
49 changes: 49 additions & 0 deletions paasta_tools/kubernetes_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
from kubernetes.client import V1PodTemplateSpec
from kubernetes.client import V1PreferredSchedulingTerm
from kubernetes.client import V1Probe
from kubernetes.client import V1ProjectedVolumeSource
from kubernetes.client import V1ReplicaSet
from kubernetes.client import V1ResourceRequirements
from kubernetes.client import V1RoleBinding
Expand All @@ -108,13 +109,15 @@
from kubernetes.client import V1SecretVolumeSource
from kubernetes.client import V1SecurityContext
from kubernetes.client import V1ServiceAccount
from kubernetes.client import V1ServiceAccountTokenProjection
from kubernetes.client import V1StatefulSet
from kubernetes.client import V1StatefulSetSpec
from kubernetes.client import V1Subject
from kubernetes.client import V1TCPSocketAction
from kubernetes.client import V1TopologySpreadConstraint
from kubernetes.client import V1Volume
from kubernetes.client import V1VolumeMount
from kubernetes.client import V1VolumeProjection
from kubernetes.client import V1WeightedPodAffinityTerm
from kubernetes.client import V2beta2CrossVersionObjectReference
from kubernetes.client import V2beta2HorizontalPodAutoscaler
Expand Down Expand Up @@ -171,6 +174,7 @@
from paasta_tools.utils import PaastaColors
from paasta_tools.utils import PaastaNotConfiguredError
from paasta_tools.utils import PersistentVolume
from paasta_tools.utils import ProjectedSAVolume
from paasta_tools.utils import SecretVolume
from paasta_tools.utils import SystemPaastaConfig
from paasta_tools.utils import time_cache
Expand Down Expand Up @@ -227,6 +231,9 @@
"ephemeral-storage": "256Mi",
}

DEFAULT_PROJECTED_SA_EXPIRATION_SECONDS = 3600
PROJECTED_SA_TOKEN_PATH = "token"


# conditions is None when creating a new HPA, but the client raises an error in that case.
# For detail, https://github.com/kubernetes-client/python/issues/553
Expand Down Expand Up @@ -1002,6 +1009,14 @@ def get_secret_volume_name(self, secret_volume: SecretVolume) -> str:
"secret--{name}".format(name=secret_volume["secret_name"]), length_limit=63
)

def get_projected_sa_volume_name(
self, projected_sa_volume: ProjectedSAVolume
) -> str:
return self.get_sanitised_volume_name(
"projected-sa--{audience}".format(audience=projected_sa_volume["audience"]),
length_limit=63,
)

def get_boto_secret_volume_name(self, service_name: str) -> str:
return self.get_sanitised_volume_name(
f"secret-boto-key-{service_name}", length_limit=63
Expand Down Expand Up @@ -1130,6 +1145,7 @@ def get_hacheck_sidecar_container(
aws_ebs_volumes=[],
persistent_volumes=[],
secret_volumes=[],
projected_sa_volumes=[],
),
)
return None
Expand Down Expand Up @@ -1440,6 +1456,7 @@ def get_kubernetes_containers(
aws_ebs_volumes=aws_ebs_volumes,
persistent_volumes=self.get_persistent_volumes(),
secret_volumes=secret_volumes,
projected_sa_volumes=self.get_projected_sa_volumes(),
),
)
containers = [service_container] + self.get_sidecar_containers( # type: ignore
Expand Down Expand Up @@ -1477,6 +1494,7 @@ def get_pod_volumes(
docker_volumes: Sequence[DockerVolume],
aws_ebs_volumes: Sequence[AwsEbsVolume],
secret_volumes: Sequence[SecretVolume],
projected_sa_volumes: Sequence[ProjectedSAVolume],
) -> Sequence[V1Volume]:
pod_volumes = []
unique_docker_volumes = {
Expand Down Expand Up @@ -1534,6 +1552,27 @@ def get_pod_volumes(
),
)
)
for projected_volume in projected_sa_volumes:
pod_volumes.append(
V1Volume(
name=self.get_projected_sa_volume_name(projected_volume),
projected=V1ProjectedVolumeSource(
sources=[
V1VolumeProjection(
service_account_token=V1ServiceAccountTokenProjection(
audience=projected_volume["audience"],
expiration_seconds=projected_volume.get(
"expiration_seconds",
DEFAULT_PROJECTED_SA_EXPIRATION_SECONDS,
),
path=PROJECTED_SA_TOKEN_PATH,
)
)
],
),
),
)

boto_volume = self.get_boto_volume()
if boto_volume:
pod_volumes.append(boto_volume)
Expand Down Expand Up @@ -1694,6 +1733,7 @@ def get_volume_mounts(
aws_ebs_volumes: Sequence[AwsEbsVolume],
persistent_volumes: Sequence[PersistentVolume],
secret_volumes: Sequence[SecretVolume],
projected_sa_volumes: Sequence[ProjectedSAVolume],
) -> Sequence[V1VolumeMount]:
volume_mounts = (
[
Expand Down Expand Up @@ -1728,6 +1768,14 @@ def get_volume_mounts(
)
for volume in secret_volumes
]
+ [
V1VolumeMount(
mount_path=volume["container_path"],
name=self.get_projected_sa_volume_name(volume),
read_only=True,
)
for volume in projected_sa_volumes
]
)
if self.config_dict.get("boto_keys", []):
secret_hash = self.get_boto_secret_hash()
Expand Down Expand Up @@ -2140,6 +2188,7 @@ def get_pod_template_spec(
docker_volumes=docker_volumes + hacheck_sidecar_volumes,
aws_ebs_volumes=self.get_aws_ebs_volumes(),
secret_volumes=self.get_secret_volumes(),
projected_sa_volumes=self.get_projected_sa_volumes(),
),
)
# need to check if there are node selectors/affinities. if there are none
Expand Down
10 changes: 10 additions & 0 deletions paasta_tools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ class SecretVolume(TypedDict, total=False):
items: List[SecretVolumeItem]


class ProjectedSAVolume(TypedDict, total=False):
container_path: str
audience: str
expiration_seconds: int


class TronSecretVolume(SecretVolume, total=False):
secret_volume_name: str

Expand Down Expand Up @@ -331,6 +337,7 @@ class InstanceConfigDict(TypedDict, total=False):
extra_volumes: List[DockerVolume]
aws_ebs_volumes: List[AwsEbsVolume]
secret_volumes: List[SecretVolume]
projected_sa_volumes: List[ProjectedSAVolume]
security: SecurityConfigDict
dependencies_reference: str
dependencies: Dict[str, Dict]
Expand Down Expand Up @@ -960,6 +967,9 @@ def get_aws_ebs_volumes(self) -> List[AwsEbsVolume]:
def get_secret_volumes(self) -> List[SecretVolume]:
return self.config_dict.get("secret_volumes", [])

def get_projected_sa_volumes(self) -> List[ProjectedSAVolume]:
return self.config_dict.get("projected_sa_volumes", [])

def get_iam_role(self) -> str:
return self.config_dict.get("iam_role", "")

Expand Down
38 changes: 38 additions & 0 deletions tests/test_kubernetes_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from kubernetes.client import V1PodTemplateSpec
from kubernetes.client import V1PreferredSchedulingTerm
from kubernetes.client import V1Probe
from kubernetes.client import V1ProjectedVolumeSource
from kubernetes.client import V1ResourceRequirements
from kubernetes.client import V1RoleBinding
from kubernetes.client import V1RoleRef
Expand All @@ -54,13 +55,15 @@
from kubernetes.client import V1SecurityContext
from kubernetes.client import V1ServiceAccount
from kubernetes.client import V1ServiceAccountList
from kubernetes.client import V1ServiceAccountTokenProjection
from kubernetes.client import V1StatefulSet
from kubernetes.client import V1StatefulSetSpec
from kubernetes.client import V1Subject
from kubernetes.client import V1TCPSocketAction
from kubernetes.client import V1TopologySpreadConstraint
from kubernetes.client import V1Volume
from kubernetes.client import V1VolumeMount
from kubernetes.client import V1VolumeProjection
from kubernetes.client import V2beta2CrossVersionObjectReference
from kubernetes.client import V2beta2HorizontalPodAutoscaler
from kubernetes.client import V2beta2HorizontalPodAutoscalerSpec
Expand Down Expand Up @@ -153,6 +156,7 @@
from paasta_tools.utils import DeploymentVersion
from paasta_tools.utils import DockerVolume
from paasta_tools.utils import PersistentVolume
from paasta_tools.utils import ProjectedSAVolume
from paasta_tools.utils import SecretVolume
from paasta_tools.utils import SecretVolumeItem
from paasta_tools.utils import SystemPaastaConfig
Expand Down Expand Up @@ -1098,6 +1102,13 @@ def test_get_pod_volumes(self):
],
),
]
mock_projected_sa_volumes = [
ProjectedSAVolume(
container_path="/var/secret/something",
audience="a.b.c",
expiration_seconds=1234,
)
]
expected_volumes = [
V1Volume(
host_path=V1HostPathVolumeSource(path="/nail/blah"),
Expand Down Expand Up @@ -1145,12 +1156,27 @@ def test_get_pod_volumes(self):
optional=False,
),
),
V1Volume(
name="projected-sa--adot-bdot-c",
projected=V1ProjectedVolumeSource(
sources=[
V1VolumeProjection(
service_account_token=V1ServiceAccountTokenProjection(
audience="a.b.c",
expiration_seconds=1234,
path="token",
)
),
],
),
),
]
assert (
self.deployment.get_pod_volumes(
docker_volumes=mock_docker_volumes + mock_hacheck_volumes,
aws_ebs_volumes=mock_aws_ebs_volumes,
secret_volumes=mock_secret_volumes,
projected_sa_volumes=mock_projected_sa_volumes,
)
== expected_volumes
)
Expand Down Expand Up @@ -1186,6 +1212,12 @@ def test_get_volume_mounts(self):
mock_secret_volumes = [
SecretVolume(container_path="/garply", secret_name="waldo")
]
mock_projected_sa_volumes = [
ProjectedSAVolume(
container_path="/var/secret/something",
audience="a.b.c",
)
]
expected_volumes = [
V1VolumeMount(
mount_path="/nail/foo", name="some-volume", read_only=True
Expand All @@ -1198,13 +1230,19 @@ def test_get_volume_mounts(self):
),
V1VolumeMount(mount_path="/blah", name="some-volume", read_only=False),
V1VolumeMount(mount_path="/garply", name="some-volume", read_only=True),
V1VolumeMount(
mount_path="/var/secret/something",
name="some-volume",
read_only=True,
),
]
assert (
self.deployment.get_volume_mounts(
docker_volumes=mock_docker_volumes,
aws_ebs_volumes=mock_aws_ebs_volumes,
persistent_volumes=mock_persistent_volumes,
secret_volumes=mock_secret_volumes,
projected_sa_volumes=mock_projected_sa_volumes,
)
== expected_volumes
)
Expand Down

0 comments on commit b2288ae

Please sign in to comment.