feat(apiserver): new 10 Kubernetes ApiServer checks (#3289)

This commit is contained in:
Sergio Garcia
2024-02-21 13:29:28 +01:00
committed by GitHub
parent b40f32ab57
commit 636892bc9a
32 changed files with 674 additions and 1 deletions
@@ -23,6 +23,7 @@ class apiserver_always_pull_images_plugin(Check):
if command.startswith("--enable-admission-plugins"):
if "AlwaysPullImages" in command:
plugin_set = True
break
if not plugin_set:
break
if not plugin_set:
@@ -22,7 +22,6 @@ class apiserver_audit_log_path_set(Check):
# Check if "--audit-log-path" is set
if "--audit-log-path" in str(container.command):
audit_log_path_set = True
break
if not audit_log_path_set:
break
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_client_ca_file_set",
"CheckTitle": "Ensure that the --client-ca-file argument is set as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "TLS Authentication",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with the --client-ca-file argument, specifying the CA file for client authentication. This setting enables the API server to authenticate clients using certificates signed by the CA and is crucial for secure communication.",
"Risk": "If the client CA file is not set, the API server may not properly authenticate clients, potentially leading to unauthorized access.",
"RelatedUrl": "https://kubernetes.io/docs/setup/best-practices/certificates/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to include the --client-ca-file parameter with the appropriate CA file. Example: --client-ca-file=<path/to/client-ca-file>",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure the API server is configured with a client CA file for secure client authentication.",
"Url": "https://kubernetes.io/docs/setup/best-practices/certificates/#certificate-paths"
}
},
"Categories": [
"Access Control",
"TLS Configuration"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "The client CA file is a critical component of TLS authentication and should be properly managed and securely stored."
}
@@ -0,0 +1,31 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_client_ca_file_set(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = f"Client CA file is set appropriately in the API server in pod {pod.name}."
client_ca_file_set = False
for container in pod.containers.values():
client_ca_file_set = False
# Check if "--client-ca-file" is set
if "--client-ca-file" in str(container.command):
client_ca_file_set = True
if not client_ca_file_set:
break
if not client_ca_file_set:
report.status = "FAIL"
report.status_extended = f"Client CA file is not set in pod {pod.name}."
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_deny_service_external_ips",
"CheckTitle": "Ensure that the DenyServiceExternalIPs is set",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Admission Controllers",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures the DenyServiceExternalIPs admission controller is enabled, which rejects all new usage of the Service field externalIPs. Enabling this controller enhances security by preventing the misuse of the externalIPs field.",
"Risk": "Not setting the DenyServiceExternalIPs admission controller could allow users to create Services with external IPs, potentially exposing services to security risks.",
"RelatedUrl": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#denyserviceexternalips",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver manifest to include '--disable-admission-plugins=DenyServiceExternalIPs' in the API server's command arguments.",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable the DenyServiceExternalIPs admission controller by setting the '--disable-admission-plugins' argument in the kube-apiserver configuration.",
"Url": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#how-do-i-turn-off-an-admission-controller"
}
},
"Categories": [
"Network Policy",
"Security Best Practices"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Consider the impact on existing services before enabling this admission controller, as it can restrict the usage of external IPs in the cluster."
}
@@ -0,0 +1,30 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_deny_service_external_ips(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = f"API Server has DenyServiceExternalIPs admission controller enabled in pod {pod.name}."
deny_service_external_ips = False
for container in pod.containers.values():
deny_service_external_ips = False
for command in container.command:
if command.startswith("--disable-admission-plugins"):
if "DenyServiceExternalIPs" in (command.split("=")[1]):
deny_service_external_ips = True
if not deny_service_external_ips:
break
if not deny_service_external_ips:
report.status = "FAIL"
report.status_extended = f"API Server does not have DenyServiceExternalIPs enabled in pod {pod.name}."
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_disable_profiling",
"CheckTitle": "Ensure that the --profiling argument is set to false",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Performance",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that profiling is disabled in the Kubernetes API server. Profiling generates extensive data about the system's performance and operations, which, if not needed, should be disabled to reduce the attack surface.",
"Risk": "Enabled profiling can potentially expose detailed system and program data, which might be exploited for malicious purposes.",
"RelatedUrl": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to set the --profiling argument to false. Example: --profiling=false",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Disable profiling in the API server unless it is necessary for troubleshooting performance bottlenecks.",
"Url": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"
}
},
"Categories": [
"Security Best Practices",
"Configuration Management"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Profiling is enabled by default in Kubernetes. Disabling it when not needed helps in securing the cluster."
}
@@ -0,0 +1,29 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_disable_profiling(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = f"Profiling is disabled in pod {pod.name}."
profiling_enabled = False
for container in pod.containers.values():
profiling_enabled = False
# Check if "--profiling" is set to false
if "--profiling=false" not in str(container.command):
profiling_enabled = True
break
if profiling_enabled:
report.status = "FAIL"
report.status_extended = f"Profiling is enabled in pod {pod.name}."
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_encryption_provider_config_set",
"CheckTitle": "Ensure that the --encryption-provider-config argument is set as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Data Encryption",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with the --encryption-provider-config argument to encrypt sensitive data at rest in the etcd key-value store. Encrypting data at rest prevents potential unauthorized disclosures and ensures that the sensitive data is secure.",
"Risk": "Without proper configuration of the encryption provider, sensitive data stored in etcd might not be encrypted, posing a risk of data breaches.",
"RelatedUrl": "https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to include the --encryption-provider-config parameter with the path to the EncryptionConfig file. Example: --encryption-provider-config=/path/to/EncryptionConfig/File",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure and enable encryption for data at rest in etcd using a suitable EncryptionConfig file.",
"Url": "https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/#determining-whether-encryption-at-rest-is-already-enabled"
}
},
"Categories": [
"Data Security",
"Configuration Optimization"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Ensure that the EncryptionConfig file is correctly configured and securely stored."
}
@@ -0,0 +1,34 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_encryption_provider_config_set(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = (
f"Encryption provider config is set appropriately in pod {pod.name}."
)
encryption_provider_config_set = True
for container in pod.containers.values():
# Check if "--encryption-provider-config" is set
if "--encryption-provider-config" not in str(container.command):
encryption_provider_config_set = False
break
if not encryption_provider_config_set:
report.status = "FAIL"
report.status_extended = (
f"Encryption provider config is not set in pod {pod.name}."
)
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_etcd_cafile_set",
"CheckTitle": "Ensure that the --etcd-cafile argument is set as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "etcd Connection",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with the --etcd-cafile argument, specifying the Certificate Authority file for etcd client connections. This setting is important for secure communication with etcd and ensures that the API server connects to etcd with an SSL Certificate Authority file.",
"Risk": "Without proper TLS configuration, communication between the API server and etcd can be unencrypted, leading to potential security vulnerabilities.",
"RelatedUrl": "https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to include the --etcd-cafile parameter with the appropriate CA file. Example: --etcd-cafile=<path/to/ca-file>",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure etcd connections from the API server are secured using the appropriate CA file.",
"Url": "https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#limiting-access-of-etcd-clusters"
}
},
"Categories": [
"Data Security",
"TLS Configuration"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "It is crucial to manage and rotate the CA file securely as part of your cluster's security practices."
}
@@ -0,0 +1,31 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_etcd_cafile_set(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = (
f"etcd CA file is set appropriately in pod {pod.name}."
)
etcd_cafile_set = True
for container in pod.containers.values():
# Check if "--etcd-cafile" is set
if "--etcd-cafile" not in str(container.command):
etcd_cafile_set = False
break
if not etcd_cafile_set:
report.status = "FAIL"
report.status_extended = f"etcd CA file is not set in pod {pod.name}."
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_etcd_tls_config",
"CheckTitle": "Ensure that the --etcd-certfile and --etcd-keyfile arguments are set as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "etcd Connection",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with TLS encryption for etcd client connections, using --etcd-certfile and --etcd-keyfile arguments. Setting up TLS for etcd is crucial for securing the sensitive data stored in etcd as it's the primary datastore for Kubernetes.",
"Risk": "Without TLS encryption, data stored in etcd is susceptible to eavesdropping and man-in-the-middle attacks, potentially leading to data breaches.",
"RelatedUrl": "https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to include TLS parameters for etcd connection. Example: --etcd-certfile=<path/to/client-certificate-file> --etcd-keyfile=<path/to/client-key-file>",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable TLS encryption for etcd client connections to secure sensitive data.",
"Url": "https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#limiting-access-of-etcd-clusters"
}
},
"Categories": [
"Data Security",
"Configuration Optimization"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "TLS encryption for etcd is not enabled by default and should be explicitly configured."
}
@@ -0,0 +1,35 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_etcd_tls_config(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = (
f"TLS configuration for etcd is set appropriately in pod {pod.name}."
)
etcd_tls_config_set = True
for container in pod.containers.values():
# Check if "--etcd-certfile" and "--etcd-keyfile" are set
if "--etcd-certfile" not in str(
container.command
) and "--etcd-keyfile" not in str(container.command):
etcd_tls_config_set = False
break
if not etcd_tls_config_set:
report.status = "FAIL"
report.status_extended = (
f"TLS configuration for etcd is not set in pod {pod.name}."
)
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_event_rate_limit",
"CheckTitle": "Ensure that the admission control plugin EventRateLimit is set",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Admission Control",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check verifies if the Kubernetes API server is configured with the EventRateLimit admission control plugin. This plugin limits the rate of events accepted by the API Server, preventing potential DoS attacks by misbehaving workloads.",
"Risk": "Without EventRateLimit, the API server could be overwhelmed by a high number of events, leading to DoS and performance issues.",
"RelatedUrl": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to include EventRateLimit in the --enable-admission-plugins argument and specify a configuration file. Example: --enable-admission-plugins=...,EventRateLimit,... --admission-control-config-file=/path/to/configuration/file",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure EventRateLimit as an admission control plugin for the API server to manage the rate of incoming events effectively.",
"Url": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#eventratelimit"
}
},
"Categories": [
"Resource Management",
"Security Best Practices"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Tuning EventRateLimit requires careful consideration of the specific requirements of your environment."
}
@@ -0,0 +1,34 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_event_rate_limit(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = (
f"EventRateLimit admission control plugin is set in pod {pod.name}."
)
plugin_set = False
for container in pod.containers.values():
plugin_set = False
for command in container.command:
if command.startswith("--enable-admission-plugins"):
if "EventRateLimit" not in (command.split("=")[1]):
plugin_set = True
break
if not plugin_set:
break
if not plugin_set:
report.status = "FAIL"
report.status_extended = f"EventRateLimit admission control plugin is not set in pod {pod.name}."
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_kubelet_cert_auth",
"CheckTitle": "Ensure that the --kubelet-certificate-authority argument is set as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "TLS Verification",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is set up with a specified certificate authority for kubelet connections, using the --kubelet-certificate-authority argument. This setup is crucial for verifying the kubelet's certificate to prevent man-in-the-middle attacks during connections from the apiserver to the kubelet.",
"Risk": "Without the --kubelet-certificate-authority argument, connections to kubelets are not verified, increasing the risk of man-in-the-middle attacks, especially over untrusted networks.",
"RelatedUrl": "https://kubernetes.io/docs/setup/best-practices/certificates/",
"Remediation": {
"Code": {
"CLI": "Set the --kubelet-certificate-authority argument in the kube-apiserver configuration to the path of the CA certificate file. Example: --kubelet-certificate-authority=/path/to/ca-file",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable TLS verification between the apiserver and kubelets by specifying the certificate authority in the kube-apiserver configuration.",
"Url": "https://kubernetes.io/docs/setup/best-practices/certificates/#configure-certificates-manually"
}
},
"Categories": [
"Cluster Security",
"Communication Security"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "By default, the kube-apiserver does not verify kubelet certificates. Enabling this setting enhances the security of master-node communications."
}
@@ -0,0 +1,23 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_kubelet_cert_auth(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = f"API Server has appropriate kubelet certificate authority configured in pod {pod.name}."
for container in pod.containers.values():
if "--kubelet-certificate-authority" not in str(container.command):
report.status = "FAIL"
report.status_extended = f"API Server is missing kubelet certificate authority configuration in pod {pod.name}."
break
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_kubelet_tls_auth",
"CheckTitle": "Ensure that the --kubelet-client-certificate and --kubelet-client-key arguments are set as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "TLS Authentication",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is set up with certificate-based authentication to the kubelet. This setup requires the --kubelet-client-certificate and --kubelet-client-key arguments in the kube-apiserver configuration to be set, ensuring secure communication between the API server and kubelets.",
"Risk": "Without certificate-based authentication to kubelets, requests from the apiserver are treated as anonymous, which could lead to unauthorized access and manipulation of node resources.",
"RelatedUrl": "https://kubernetes.io/docs/setup/best-practices/certificates/",
"Remediation": {
"Code": {
"CLI": "Set the --kubelet-client-certificate and --kubelet-client-key arguments in the kube-apiserver configuration. Example: --kubelet-client-certificate=/path/to/client-certificate-file --kubelet-client-key=/path/to/client-key-file",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable TLS authentication between the apiserver and kubelets by specifying the client certificate and key in the kube-apiserver configuration.",
"Url": "https://kubernetes.io/docs/setup/best-practices/certificates/#configure-certificates-manually"
}
},
"Categories": [
"Cluster Security",
"Communication Security"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "By default, the kube-apiserver does not authenticate to kubelets using certificates. Enabling this increases the security posture of the cluster."
}
@@ -0,0 +1,26 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_kubelet_tls_auth(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = f"API Server has appropriate kubelet TLS authentication configured in pod {pod.name}."
for container in pod.containers.values():
if "--kubelet-client-certificate" not in str(
container.command
) and "--kubelet-client-key" not in str(container.command):
report.status = "FAIL"
report.status_extended = f"API Server is missing kubelet TLS authentication arguments in pod {pod.name}."
break
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_namespace_lifecycle_plugin",
"CheckTitle": "Ensure that the admission control plugin NamespaceLifecycle is set",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Admission Control",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check verifies that the NamespaceLifecycle admission control plugin is enabled in the Kubernetes API server. This plugin prevents the creation of objects in non-existent or terminating namespaces, enforcing the integrity of the namespace lifecycle and availability of new objects.",
"Risk": "Without NamespaceLifecycle, objects may be created in namespaces that are being terminated, potentially leading to inconsistencies and resource conflicts.",
"RelatedUrl": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to ensure that NamespaceLifecycle is included in the --enable-admission-plugins argument. Remove the plugin from --disable-admission-plugins if present.",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable the NamespaceLifecycle admission control plugin in the API server to enforce proper namespace management.",
"Url": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#namespacelifecycle"
}
},
"Categories": [
"Namespace Management",
"Cluster Security"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "NamespaceLifecycle plugin is usually enabled by default, ensuring proper management of namespace creation and termination."
}
@@ -0,0 +1,40 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)
class apiserver_namespace_lifecycle_plugin(Check):
def execute(self) -> Check_Report_Kubernetes:
findings = []
for pod in apiserver_client.apiserver_pods:
report = Check_Report_Kubernetes(self.metadata())
report.namespace = pod.namespace
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = (
f"NamespaceLifecycle admission control plugin is set in pod {pod.name}."
)
namespace_lifecycle_plugin_set = False
for container in pod.containers.values():
namespace_lifecycle_plugin_set = False
# Check if "--enable-admission-plugins" includes "NamespaceLifecycle"
# and "--disable-admission-plugins" does not include "NamespaceLifecycle"
for command in container.command:
if command.startswith("--enable-admission-plugins"):
if "NamespaceLifecycle" in (command.split("=")[1]):
namespace_lifecycle_plugin_set = True
elif command.startswith("--disable-admission-plugins"):
if "NamespaceLifecycle" in (command.split("=")[1]):
namespace_lifecycle_plugin_set = False
if not namespace_lifecycle_plugin_set:
break
if not namespace_lifecycle_plugin_set:
report.status = "FAIL"
report.status_extended = f"NamespaceLifecycle admission control plugin is not set in pod {pod.name}."
findings.append(report)
return findings