assemblyline-core 4.5.1.dev427__tar.gz → 4.5.1.dev436__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/PKG-INFO +1 -1
- assemblyline_core-4.5.1.dev436/assemblyline_core/VERSION +1 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/loader/run.py +1 -1
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/controllers/interface.py +1 -10
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/controllers/kubernetes_ctl.py +28 -65
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/scaler_server.py +6 -36
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/updater/run_updater.py +15 -3
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core.egg-info/PKG-INFO +1 -1
- assemblyline_core-4.5.1.dev427/assemblyline_core/VERSION +0 -1
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/LICENCE.md +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/README.md +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/alerter/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/alerter/processing.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/alerter/run_alerter.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/archiver/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/archiver/run_archiver.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/badlist_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/dispatching/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/dispatching/__main__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/dispatching/client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/dispatching/dispatcher.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/dispatching/schedules.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/dispatching/timeout.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/expiry/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/expiry/run_expiry.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/ingester/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/ingester/__main__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/ingester/constants.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/ingester/ingester.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/es_metrics.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/heartbeat_formatter.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/helper.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/metrics_server.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/run_heartbeat_manager.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/run_metrics_aggregator.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/metrics/run_statistics_aggregator.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/plumber/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/plumber/run_plumber.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/creator/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/creator/run.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/creator/run_worker.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/loader/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/loader/run_worker.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/replay.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/safelist_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/collection.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/controllers/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/controllers/docker_ctl.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/scaler/run_scaler.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/server_base.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/signature_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/submission_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/tasking_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/updater/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/updater/helper.py +1 -1
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/crawler.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/department_map.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/safelist.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/stream_map.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/worker.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/workflow/__init__.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/workflow/run_workflow.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core.egg-info/SOURCES.txt +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core.egg-info/dependency_links.txt +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core.egg-info/requires.txt +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core.egg-info/top_level.txt +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/setup.cfg +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/setup.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_alerter.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_badlist_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_dispatcher.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_expiry.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_plumber.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_replay.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_safelist_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_scaler.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_scheduler.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_signature_client.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_simulation.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_vacuum.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_worker_ingest.py +0 -0
- {assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_worker_submit.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
4.5.1.dev436
|
@@ -1,7 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from typing import TYPE_CHECKING, Optional
|
3
3
|
|
4
|
-
|
5
4
|
if TYPE_CHECKING:
|
6
5
|
from assemblyline_core.scaler.scaler_server import ServiceProfile
|
7
6
|
|
@@ -12,14 +11,6 @@ class ServiceControlError(RuntimeError):
|
|
12
11
|
self.service_name = service_name
|
13
12
|
|
14
13
|
|
15
|
-
class ContainerEvent:
|
16
|
-
def __init__(self, object_name: str, message: str, service_name=None, updater=None) -> None:
|
17
|
-
self.object_name = object_name
|
18
|
-
self.message = message
|
19
|
-
self.service_name = service_name
|
20
|
-
self.updater = updater
|
21
|
-
|
22
|
-
|
23
14
|
class ControllerInterface:
|
24
15
|
def add_profile(self, profile, scale=0):
|
25
16
|
"""Tell the controller about a service profile it needs to manage."""
|
@@ -59,7 +50,7 @@ class ControllerInterface:
|
|
59
50
|
def get_running_container_names(self):
|
60
51
|
raise NotImplementedError()
|
61
52
|
|
62
|
-
def new_events(self)
|
53
|
+
def new_events(self):
|
63
54
|
return []
|
64
55
|
|
65
56
|
def stateful_container_key(self, service_name: str, container_name: str, spec, change_key: str) -> Optional[str]:
|
@@ -26,11 +26,12 @@ from kubernetes.client import V1Deployment, V1DeploymentSpec, V1PodTemplateSpec,
|
|
26
26
|
V1PersistentVolumeClaimSpec, V1NetworkPolicy, V1NetworkPolicySpec, V1NetworkPolicyEgressRule, V1NetworkPolicyPeer, \
|
27
27
|
V1NetworkPolicyIngressRule, V1Secret, V1SecretVolumeSource, V1LocalObjectReference, V1Service, \
|
28
28
|
V1ServiceSpec, V1ServicePort, V1PodSecurityContext, V1Probe, V1ExecAction, V1SecurityContext, \
|
29
|
-
V1Affinity, V1NodeAffinity, V1NodeSelector, V1NodeSelectorTerm, V1NodeSelectorRequirement,
|
29
|
+
V1Affinity, V1NodeAffinity, V1NodeSelector, V1NodeSelectorTerm, V1NodeSelectorRequirement, V1Toleration, \
|
30
|
+
V1Capabilities, V1SeccompProfile
|
30
31
|
from kubernetes.client.rest import ApiException
|
31
32
|
from assemblyline.odm.models.service import DependencyConfig, DockerConfig, PersistentVolume
|
32
33
|
|
33
|
-
from assemblyline_core.scaler.controllers.interface import
|
34
|
+
from assemblyline_core.scaler.controllers.interface import ControllerInterface
|
34
35
|
|
35
36
|
# RESERVE_MEMORY_PER_NODE = os.environ.get('RESERVE_MEMORY_PER_NODE')
|
36
37
|
|
@@ -45,6 +46,14 @@ SERVICE_LIVENESS_TIMEOUT = int(os.environ.get('SERVICE_LIVENESS_TIMEOUT', 60))
|
|
45
46
|
UNPRIVILEGED_SERVICE_ACCOUNT_NAME = os.environ.get('UNPRIVILEGED_SERVICE_ACCOUNT_NAME', None)
|
46
47
|
PRIVILEGED_SERVICE_ACCOUNT_NAME = os.environ.get('PRIVILEGED_SERVICE_ACCOUNT_NAME', None)
|
47
48
|
CERTIFICATE_VALIDITY_PERIOD = int(os.environ.get('CERTIFICATE_VALIDITY_PERIOD', '36500'))
|
49
|
+
RESTRICTED_POD_SECURITY_CONTEXT = V1SecurityContext(
|
50
|
+
run_as_user=1000,
|
51
|
+
run_as_group=1000,
|
52
|
+
capabilities=V1Capabilities(drop=["ALL"]),
|
53
|
+
run_as_non_root=True,
|
54
|
+
allow_privilege_escalation=False,
|
55
|
+
seccomp_profile=V1SeccompProfile(type="RuntimeDefault")
|
56
|
+
)
|
48
57
|
|
49
58
|
AL_ROOT_CA = os.environ.get('AL_ROOT_CA', '/etc/assemblyline/ssl/al_root-ca.crt')
|
50
59
|
AL_ROOT_CA_PK = os.environ.get('AL_ROOT_CA_PK', '/etc/assemblyline/ssl/al_root-ca.key')
|
@@ -241,7 +250,8 @@ def parse_cpu(string: str) -> float:
|
|
241
250
|
class KubernetesController(ControllerInterface):
|
242
251
|
def __init__(self, logger, namespace: str, prefix: str, priority: str, dependency_priority: str,
|
243
252
|
cpu_reservation: float, linux_node_selector: Selector, labels=None, log_level="INFO", core_env={},
|
244
|
-
default_service_account=None, cluster_pod_list=True,
|
253
|
+
default_service_account=None, cluster_pod_list=True, enable_pod_security=False,
|
254
|
+
default_service_tolerations=[],
|
245
255
|
priv_labels=None):
|
246
256
|
# Try loading a kubernetes connection from either the fact that we are running
|
247
257
|
# inside of a cluster, or have a config file that tells us how
|
@@ -264,7 +274,7 @@ class KubernetesController(ControllerInterface):
|
|
264
274
|
config.load_kube_config(client_configuration=cfg)
|
265
275
|
|
266
276
|
self.running: bool = True
|
267
|
-
self.prefix: str = prefix.lower()
|
277
|
+
self.prefix: str = prefix.lower()
|
268
278
|
self.priority: str = priority
|
269
279
|
self.dependency_priority: str = dependency_priority
|
270
280
|
self.cpu_reservation: float = max(0.0, min(cpu_reservation, 1.0))
|
@@ -287,6 +297,7 @@ class KubernetesController(ControllerInterface):
|
|
287
297
|
self._service_limited_env: dict[str, dict[str, str]] = defaultdict(dict)
|
288
298
|
self.default_service_account: Optional[str] = default_service_account
|
289
299
|
self.cluster_pod_list = cluster_pod_list
|
300
|
+
self.security_policy = RESTRICTED_POD_SECURITY_CONTEXT if enable_pod_security else None
|
290
301
|
self.default_service_tolerations = [V1Toleration(**toleration.as_primitives()) for toleration in default_service_tolerations]
|
291
302
|
|
292
303
|
# A record of previously reported events so that we don't report the same message repeatedly, fill it with
|
@@ -396,7 +407,8 @@ class KubernetesController(ControllerInterface):
|
|
396
407
|
"""Tell the controller about a service profile it needs to manage."""
|
397
408
|
self._create_deployment(profile.name, self._deployment_name(profile.name),
|
398
409
|
profile.container_config, profile.shutdown_seconds, scale,
|
399
|
-
change_key=profile.config_blob, core_mounts=profile.privileged
|
410
|
+
change_key=profile.config_blob, core_mounts=profile.privileged,
|
411
|
+
security_context=self.security_policy),
|
400
412
|
self._external_profiles[profile.name] = profile
|
401
413
|
|
402
414
|
def _loop_forever(self, function):
|
@@ -679,7 +691,7 @@ class KubernetesController(ControllerInterface):
|
|
679
691
|
return self._quota_mem_limit - self._get_pod_used_namespace_ram(), self._quota_mem_limit
|
680
692
|
return self._node_pool_max_ram - self._get_pod_used_ram(), self._node_pool_max_ram
|
681
693
|
|
682
|
-
def _create_containers(self, service_name: str, deployment_name: str, container_config, mounts,
|
694
|
+
def _create_containers(self, service_name: str, deployment_name: str, container_config, mounts, security_context,
|
683
695
|
core_container=False):
|
684
696
|
cores = container_config.cpu_cores
|
685
697
|
memory = container_config.ram_mb
|
@@ -719,6 +731,7 @@ class KubernetesController(ControllerInterface):
|
|
719
731
|
env=environment_variables,
|
720
732
|
image_pull_policy=image_pull_policy,
|
721
733
|
volume_mounts=mounts,
|
734
|
+
security_context=security_context,
|
722
735
|
resources=V1ResourceRequirements(
|
723
736
|
limits={'cpu': cores, 'memory': f'{memory}Mi'},
|
724
737
|
requests={'cpu': cores*self.cpu_reservation, 'memory': f'{min_memory}Mi'},
|
@@ -731,7 +744,8 @@ class KubernetesController(ControllerInterface):
|
|
731
744
|
shutdown_seconds: int, scale: int, labels: dict[str, str] = None,
|
732
745
|
volumes: list[V1Volume] = None, mounts: list[V1VolumeMount] = None,
|
733
746
|
core_mounts: bool = False, change_key: str = '', high_priority: bool = False,
|
734
|
-
deployment_strategy: V1DeploymentStrategy = V1DeploymentStrategy()
|
747
|
+
deployment_strategy: V1DeploymentStrategy = V1DeploymentStrategy(),
|
748
|
+
security_context: V1SecurityContext = None):
|
735
749
|
# Build a cache key to check for changes, just trying to only patch what changed
|
736
750
|
# will still potentially result in a lot of restarts due to different kubernetes
|
737
751
|
# systems returning differently formatted data
|
@@ -742,7 +756,8 @@ class KubernetesController(ControllerInterface):
|
|
742
756
|
key_labels += sorted(deployment_labels.items())
|
743
757
|
change_key = str(f"n={deployment_name}{change_key}dc={docker_config}ss={shutdown_seconds}"
|
744
758
|
f"l={key_labels}v={volumes}m={mounts}cm={core_mounts}senv={svc_env}"
|
745
|
-
f"nodes={field_selector or ''}{label_selector or ''}"
|
759
|
+
f"nodes={field_selector or ''}{label_selector or ''}"
|
760
|
+
f"security_context={security_context or ''}")
|
746
761
|
self.logger.debug(f"{deployment_name} actual change_key: {change_key}")
|
747
762
|
change_key = str(hash(change_key))
|
748
763
|
|
@@ -847,7 +862,7 @@ class KubernetesController(ControllerInterface):
|
|
847
862
|
init_containers=init_containers,
|
848
863
|
volumes=all_volumes,
|
849
864
|
containers=self._create_containers(service_name, deployment_name, docker_config,
|
850
|
-
all_mounts, core_container=core_mounts),
|
865
|
+
all_mounts, security_context, core_container=core_mounts),
|
851
866
|
priority_class_name=self.dependency_priority if high_priority else self.priority,
|
852
867
|
termination_grace_period_seconds=shutdown_seconds,
|
853
868
|
security_context=V1PodSecurityContext(fs_group=1000),
|
@@ -952,58 +967,14 @@ class KubernetesController(ControllerInterface):
|
|
952
967
|
def restart(self, service):
|
953
968
|
self._create_deployment(service.name, self._deployment_name(service.name), service.container_config,
|
954
969
|
service.shutdown_seconds, self.get_target(service.name), core_mounts=service.privileged,
|
955
|
-
change_key=service.config_blob)
|
970
|
+
change_key=service.config_blob, security_context=self.security_policy)
|
956
971
|
|
957
972
|
def get_running_container_names(self):
|
958
973
|
pods = self.api.list_pod_for_all_namespaces(field_selector='status.phase==Running',
|
959
974
|
_request_timeout=API_TIMEOUT)
|
960
975
|
return [pod.metadata.name for pod in pods.items]
|
961
976
|
|
962
|
-
|
963
|
-
def dropped_message(event: CoreV1Event) -> bool:
|
964
|
-
"""These aren't messages anyone looking at the """
|
965
|
-
|
966
|
-
# These are common ephemeral states
|
967
|
-
if event.action in ["Scheduling"]:
|
968
|
-
return True
|
969
|
-
if event.reason in ["BackOff", "NodeNotReady", "FailedGetResourceMetric", "FailedComputeMetricsReplicas"]:
|
970
|
-
return True
|
971
|
-
|
972
|
-
# There is a more detailed event that starts with "Failed to pull image"
|
973
|
-
if event.message == "Error: ErrImagePull":
|
974
|
-
return True
|
975
|
-
if event.message == "Error: ImagePullBackOff":
|
976
|
-
return True
|
977
|
-
|
978
|
-
# Probes failing on exiting containers is normal
|
979
|
-
if "Readiness probe errored" in event.message and "container is in CONTAINER_EXITED state" in event.message:
|
980
|
-
return True
|
981
|
-
if "Liveness probe errored" in event.message and "container is in CONTAINER_EXITED state" in event.message:
|
982
|
-
return True
|
983
|
-
|
984
|
-
return False
|
985
|
-
|
986
|
-
def parse_container_name(self, name) -> tuple[Optional[str], Optional[bool]]:
|
987
|
-
if not name.startswith(self.prefix):
|
988
|
-
return (None, None)
|
989
|
-
name = name.removeprefix(self.prefix)
|
990
|
-
|
991
|
-
name, _, container_id = name.rpartition('-')
|
992
|
-
if not container_id:
|
993
|
-
return (None, None)
|
994
|
-
|
995
|
-
name, _, deployment_id = name.rpartition('-')
|
996
|
-
if not deployment_id:
|
997
|
-
return (None, None)
|
998
|
-
|
999
|
-
updater = False
|
1000
|
-
if name.endswith('-updates'):
|
1001
|
-
name = name.removesuffix('-updates')
|
1002
|
-
updater = True
|
1003
|
-
|
1004
|
-
return (name, updater)
|
1005
|
-
|
1006
|
-
def new_events(self) -> list[ContainerEvent]:
|
977
|
+
def new_events(self):
|
1007
978
|
response = self.api.list_namespaced_event(namespace=self.namespace, pretty='false',
|
1008
979
|
field_selector='type=Warning', watch=False,
|
1009
980
|
_request_timeout=API_TIMEOUT)
|
@@ -1013,15 +984,7 @@ class KubernetesController(ControllerInterface):
|
|
1013
984
|
for event in response.items:
|
1014
985
|
if self.events_window.get(event.metadata.uid, 0) != event.count:
|
1015
986
|
self.events_window[event.metadata.uid] = event.count
|
1016
|
-
|
1017
|
-
if KubernetesController.dropped_message(event):
|
1018
|
-
continue
|
1019
|
-
|
1020
|
-
object_name = event.involved_object.name
|
1021
|
-
service_name, is_updater = None, None
|
1022
|
-
if event.involved_object.kind == 'Pod':
|
1023
|
-
service_name, is_updater = self.parse_container_name(object_name)
|
1024
|
-
new.append(ContainerEvent(object_name, event.message, service_name, is_updater))
|
987
|
+
new.append(event.involved_object.name + ': ' + event.message)
|
1025
988
|
|
1026
989
|
# Flush out events that have moved outside the window
|
1027
990
|
old = set(self.events_window.keys()) - {event.metadata.uid for event in response.items}
|
@@ -1187,7 +1150,7 @@ class KubernetesController(ControllerInterface):
|
|
1187
1150
|
self._create_deployment(service_name, deployment_name, spec.container,
|
1188
1151
|
30, 1, labels, volumes=volumes, mounts=mounts, high_priority=True,
|
1189
1152
|
core_mounts=spec.run_as_core, change_key=change_key,
|
1190
|
-
deployment_strategy=deployment_strategy)
|
1153
|
+
deployment_strategy=deployment_strategy, security_context=self.security_policy)
|
1191
1154
|
|
1192
1155
|
# Setup a service to direct to the deployment
|
1193
1156
|
try:
|
@@ -27,19 +27,17 @@ from assemblyline.remote.datatypes.hash import ExpiringHash, Hash
|
|
27
27
|
from assemblyline.remote.datatypes.events import EventWatcher, EventSender
|
28
28
|
from assemblyline.odm.models.service import Service, DockerConfig, EnvironmentVariable
|
29
29
|
from assemblyline.odm.models.config import Mount
|
30
|
-
from assemblyline.odm.models.error import Error
|
31
30
|
from assemblyline.odm.messages.scaler_heartbeat import Metrics
|
32
31
|
from assemblyline.odm.messages.scaler_status_heartbeat import Status
|
33
32
|
from assemblyline.odm.messages.changes import ServiceChange, Operation
|
34
33
|
from assemblyline.common.dict_utils import get_recursive_sorted_tuples, flatten
|
35
|
-
from assemblyline.common.uid import get_id_from_data
|
34
|
+
from assemblyline.common.uid import get_id_from_data
|
36
35
|
from assemblyline.common.forge import get_classification, get_service_queue, get_apm_client
|
37
36
|
from assemblyline.common.constants import SCALER_TIMEOUT_QUEUE, SERVICE_STATE_HASH, ServiceStatus
|
38
37
|
from assemblyline.common.version import FRAMEWORK_VERSION, SYSTEM_VERSION
|
39
|
-
from assemblyline.common.isotime import now_as_iso
|
40
38
|
from assemblyline_core.updater.helper import get_registry_config
|
41
39
|
from assemblyline_core.scaler.controllers import KubernetesController
|
42
|
-
from assemblyline_core.scaler.controllers.interface import
|
40
|
+
from assemblyline_core.scaler.controllers.interface import ServiceControlError
|
43
41
|
from assemblyline_core.server_base import ServiceStage, ThreadedCoreBase
|
44
42
|
|
45
43
|
from .controllers import DockerController
|
@@ -54,7 +52,6 @@ SCALE_INTERVAL = 5
|
|
54
52
|
METRIC_SYNC_INTERVAL = 0.5
|
55
53
|
CONTAINER_EVENTS_LOG_INTERVAL = 2
|
56
54
|
HEARTBEAT_INTERVAL = 5
|
57
|
-
SIXTY_DAYS = 60 * 60 * 24 * 60
|
58
55
|
|
59
56
|
# The maximum containers we ask to be created in a single scaling iteration
|
60
57
|
# This is to give kubernetes a chance to update our view of resource usage before we ask for more containers
|
@@ -74,7 +71,6 @@ DOCKER_CONFIGURATION_VOLUME = os.getenv('DOCKER_CONFIGURATION_VOLUME', None)
|
|
74
71
|
|
75
72
|
SERVICE_API_HOST = os.getenv('SERVICE_API_HOST', None)
|
76
73
|
INTERNAL_ENCRYPT = bool(SERVICE_API_HOST and SERVICE_API_HOST.startswith('https'))
|
77
|
-
SERVICE_PREFIX = 'alsvc-'
|
78
74
|
|
79
75
|
|
80
76
|
@contextmanager
|
@@ -315,7 +311,7 @@ class ScalerServer(ThreadedCoreBase):
|
|
315
311
|
|
316
312
|
if KUBERNETES_AL_CONFIG:
|
317
313
|
self.log.info(f"Loading Kubernetes cluster interface on namespace: {NAMESPACE}")
|
318
|
-
self.controller = KubernetesController(logger=self.log, prefix=
|
314
|
+
self.controller = KubernetesController(logger=self.log, prefix='alsvc_', labels=labels,
|
319
315
|
namespace=NAMESPACE, priority='al-service-priority',
|
320
316
|
dependency_priority='al-core-priority',
|
321
317
|
cpu_reservation=self.config.services.cpu_reservation,
|
@@ -323,6 +319,7 @@ class ScalerServer(ThreadedCoreBase):
|
|
323
319
|
log_level=self.config.logging.log_level,
|
324
320
|
core_env=core_env,
|
325
321
|
cluster_pod_list=self.config.core.scaler.cluster_pod_list,
|
322
|
+
enable_pod_security=self.config.core.scaler.enable_pod_security,
|
326
323
|
default_service_account=self.config.services.service_account,
|
327
324
|
default_service_tolerations=service_defaults_config.tolerations,
|
328
325
|
priv_labels=priv_labels
|
@@ -983,34 +980,7 @@ class ScalerServer(ThreadedCoreBase):
|
|
983
980
|
|
984
981
|
def log_container_events(self):
|
985
982
|
"""The service status table may have references to containers that have crashed. Try to remove them all."""
|
986
|
-
pool = concurrent.futures.ThreadPoolExecutor(20)
|
987
983
|
while self.sleep(CONTAINER_EVENTS_LOG_INTERVAL):
|
988
984
|
with apm_span(self.apm_client, 'log_container_events'):
|
989
|
-
for
|
990
|
-
|
991
|
-
pool.submit(self._process_service_event, event)
|
992
|
-
continue
|
993
|
-
self.log.warning("Container Event :: " + event.object_name + ": " + event.message)
|
994
|
-
|
995
|
-
def _process_service_event(self, event: ContainerEvent):
|
996
|
-
"""Record the container event in the service event table."""
|
997
|
-
try:
|
998
|
-
message = f"Event for service {'updater' if event.updater else ''} container " + \
|
999
|
-
f"[{event.object_name}] for service: \n" + event.message
|
1000
|
-
|
1001
|
-
error = Error({
|
1002
|
-
'expiry_ts': now_as_iso(SIXTY_DAYS),
|
1003
|
-
'response': {
|
1004
|
-
'message': message,
|
1005
|
-
'service_name': event.service_name,
|
1006
|
-
'service_version': 'UNKNOWN',
|
1007
|
-
'status': 'FAIL_NONRECOVERABLE'
|
1008
|
-
},
|
1009
|
-
'sha256': '0' * 64,
|
1010
|
-
'type': 'UNKNOWN'
|
1011
|
-
})
|
1012
|
-
error_key = error.build_key(service_tool_version=get_random_id())
|
1013
|
-
self.datastore.error.save(error_key, error)
|
1014
|
-
|
1015
|
-
except Exception:
|
1016
|
-
self.log.exception("Error reporting service container event")
|
985
|
+
for message in self.controller.new_events():
|
986
|
+
self.log.warning("Container Event :: " + message)
|
@@ -15,7 +15,8 @@ import docker
|
|
15
15
|
|
16
16
|
from kubernetes.client import V1Job, V1ObjectMeta, V1JobSpec, V1PodTemplateSpec, V1PodSpec, V1Volume, \
|
17
17
|
V1VolumeMount, V1EnvVar, V1Container, V1ResourceRequirements, \
|
18
|
-
V1ConfigMapVolumeSource, V1Secret, V1SecretVolumeSource, V1LocalObjectReference, V1Toleration
|
18
|
+
V1ConfigMapVolumeSource, V1Secret, V1SecretVolumeSource, V1LocalObjectReference, V1Toleration, V1SecurityContext, \
|
19
|
+
V1Capabilities, V1SeccompProfile
|
19
20
|
from kubernetes import client, config
|
20
21
|
from kubernetes.client.rest import ApiException
|
21
22
|
|
@@ -44,6 +45,14 @@ INHERITED_VARIABLES: list[str] = ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'http
|
|
44
45
|
CONFIGURATION_HOST_PATH = os.getenv('CONFIGURATION_HOST_PATH', 'service_config')
|
45
46
|
CONFIGURATION_CONFIGMAP = os.getenv('KUBERNETES_AL_CONFIG', None)
|
46
47
|
AL_CORE_NETWORK = os.environ.get("AL_CORE_NETWORK", 'core')
|
48
|
+
RESTRICTED_POD_SECUTITY_CONTEXT = V1SecurityContext(
|
49
|
+
run_as_user=1000,
|
50
|
+
run_as_group=1000,
|
51
|
+
capabilities=V1Capabilities(drop=["ALL"]),
|
52
|
+
run_as_non_root=True,
|
53
|
+
allow_privilege_escalation=False,
|
54
|
+
seccomp_profile=V1SeccompProfile(type="RuntimeDefault")
|
55
|
+
)
|
47
56
|
|
48
57
|
SERVICE_API_HOST = os.getenv('SERVICE_API_HOST')
|
49
58
|
RELEASE_NAME = os.getenv('RELEASE_NAME')
|
@@ -148,7 +157,7 @@ class DockerUpdateInterface:
|
|
148
157
|
|
149
158
|
class KubernetesUpdateInterface:
|
150
159
|
def __init__(self, logger, prefix, namespace, priority_class, extra_labels, linux_node_selector: Selector,
|
151
|
-
log_level="INFO", default_service_account=None, default_service_tolerations=[]):
|
160
|
+
log_level="INFO", default_service_account=None, default_service_tolerations=[], enable_pod_security=False):
|
152
161
|
# Try loading a kubernetes connection from either the fact that we are running
|
153
162
|
# inside of a cluster, or we have a configuration in the normal location
|
154
163
|
try:
|
@@ -182,6 +191,7 @@ class KubernetesUpdateInterface:
|
|
182
191
|
self.secret_env = []
|
183
192
|
self.linux_node_selector = linux_node_selector
|
184
193
|
self.default_service_tolerations = [V1Toleration(**toleration.as_primitives()) for toleration in default_service_tolerations]
|
194
|
+
self.security_policy = RESTRICTED_POD_SECUTITY_CONTEXT if enable_pod_security else None
|
185
195
|
|
186
196
|
|
187
197
|
# Get the deployment of this process. Use that information to fill out the secret info
|
@@ -324,6 +334,7 @@ class KubernetesUpdateInterface:
|
|
324
334
|
env=environment_variables,
|
325
335
|
image_pull_policy='Always',
|
326
336
|
volume_mounts=volume_mounts,
|
337
|
+
security_context=self.security_policy,
|
327
338
|
resources=V1ResourceRequirements(
|
328
339
|
limits={'cpu': cores, 'memory': f'{memory}Mi'},
|
329
340
|
requests={'cpu': cores / 4, 'memory': f'{memory_min}Mi'},
|
@@ -478,7 +489,8 @@ class ServiceUpdater(ThreadedCoreBase):
|
|
478
489
|
log_level=self.config.logging.log_level,
|
479
490
|
default_service_account=self.config.services.service_account,
|
480
491
|
linux_node_selector=self.config.core.scaler.linux_node_selector,
|
481
|
-
default_service_tolerations=self.config.core.scaler.service_defaults.tolerations
|
492
|
+
default_service_tolerations=self.config.core.scaler.service_defaults.tolerations,
|
493
|
+
enable_pod_security=self.config.core.scaler.enable_pod_security)
|
482
494
|
# Add all additional mounts to privileged services
|
483
495
|
self.mounts = self.config.core.scaler.service_defaults.mounts
|
484
496
|
else:
|
@@ -1 +0,0 @@
|
|
1
|
-
4.5.1.dev427
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/client.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/replay/replay.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/server_base.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -61,6 +61,7 @@ class DockerRegistry(ContainerRegistry):
|
|
61
61
|
headers["Authorization"] = f"Bearer {token}"
|
62
62
|
|
63
63
|
resp = self._perform_request(url, headers, verify, proxies)
|
64
|
+
|
64
65
|
# Test for valid response
|
65
66
|
if resp and resp.ok:
|
66
67
|
# Test for positive list of tags
|
@@ -265,7 +266,6 @@ def get_latest_tag_for_service(service_config: ServiceConfig, system_config: Sys
|
|
265
266
|
tags = registry._get_proprietary_registry_tags(server, image_name, auth,
|
266
267
|
not system_config.services.allow_insecure_registry,
|
267
268
|
proxies, token_server)
|
268
|
-
|
269
269
|
# Pre-filter tags to only consider 'compatible' tags relative to the running system
|
270
270
|
tags = [tag for tag in tags
|
271
271
|
if re.match(f"({FRAMEWORK_VERSION})\\.({SYSTEM_VERSION})\\.\\d+\\.({update_channel})\\d+", tag)]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/assemblyline_core/vacuum/worker.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_badlist_client.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_safelist_client.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_signature_client.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_worker_ingest.py
RENAMED
File without changes
|
{assemblyline_core-4.5.1.dev427 → assemblyline_core-4.5.1.dev436}/test/test_worker_submit.py
RENAMED
File without changes
|