Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(apiserver): new 9 Kubernetes ApiServer checks #3288

Merged
merged 13 commits into from Feb 21, 2024
8 changes: 8 additions & 0 deletions prowler/config/config.yaml
Expand Up @@ -95,3 +95,11 @@ gcp:

# Kubernetes Configuration
kubernetes:

# Kubernetes API Server
# apiserver_audit_log_maxbackup_set
audit_log_maxbackup: 10
# apiserver_audit_log_maxsize_set
audit_log_maxsize: 100
# apiserver_audit_log_maxage_set
audit_log_maxage: 30
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_always_pull_images_plugin",
"CheckTitle": "Ensure that the admission control plugin AlwaysPullImages is set",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Admission Control",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check verifies that the AlwaysPullImages admission control plugin is enabled in the Kubernetes API server. This plugin ensures that every new pod always pulls the required images, enforcing image access control and preventing the use of possibly outdated or altered images.",
"Risk": "Without AlwaysPullImages, once an image is pulled to a node, any pod can use it without any authorization check, potentially leading to security risks.",
"RelatedUrl": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to include AlwaysPullImages in the --enable-admission-plugins argument. Example: --enable-admission-plugins=...,AlwaysPullImages,...",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure the API server to use the AlwaysPullImages admission control plugin to ensure image security and integrity.",
"Url": "https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers"
}
},
"Categories": [
"Image Security",
"Cluster Security"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Enabling AlwaysPullImages can increase network and registry load and decrease container startup speed. It may not be suitable for all environments."
}
@@ -0,0 +1,32 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)


class apiserver_always_pull_images_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"AlwaysPullImages admission control plugin is set in pod {pod.name}."
)
plugin_set = False
for container in pod.containers.values():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to check if all the containers in the pod has the flag enabled.

plugin_set = False
for command in container.command:
if command.startswith("--enable-admission-plugins"):
if "AlwaysPullImages" in command:
plugin_set = True
if not plugin_set:
break
if not plugin_set:
report.status = "FAIL"
report.status_extended = f"AlwaysPullImages admission control plugin is not set in pod {pod.name}."
findings.append(report)
return findings
Expand Up @@ -13,11 +13,15 @@ def execute(self) -> Check_Report_Kubernetes:
report.resource_name = pod.name
report.resource_id = pod.uid
report.status = "PASS"
report.status_extended = "API Server does not have anonymous-auth enabled."
report.status_extended = (
f"API Server does not have anonymous-auth enabled in pod {pod.name}."
)
for container in pod.containers.values():
if "--anonymous-auth=true" in container.command:
report.resource_id = container.name

report.status = "FAIL"
report.status_extended = f"API Server has anonymous-auth enabled in container {container.name}."
report.status_extended = (
f"API Server has anonymous-auth enabled in pod {pod.name}."
)
findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_audit_log_maxage_set",
"CheckTitle": "Ensure that the --audit-log-maxage argument is set to 30 or as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Auditing",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with an appropriate audit log retention period. Setting --audit-log-maxage to 30 or as per business requirements helps in maintaining logs for sufficient time to investigate past events.",
"Risk": "Without an adequate log retention period, there may be insufficient audit history to investigate and analyze past events or security incidents.",
"RelatedUrl": "https://kubernetes.io/docs/concepts/cluster-administration/audit/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to set the --audit-log-maxage argument to 30 or an appropriate number of days. Example: --audit-log-maxage=30",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure the API server audit log retention period to retain logs for at least 30 days or as per your organization's requirements.",
"Url": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"
}
},
"Categories": [
"Logging",
"Compliance"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Ensure the audit log retention period is set appropriately to balance between storage constraints and the need for historical data."
}
@@ -0,0 +1,36 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)


class apiserver_audit_log_maxage_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"Audit log max age is set appropriately in the API server in pod {pod.name}."
audit_log_maxage_set = False
for container in pod.containers.values():
audit_log_maxage_set = False
# Check if "--audit-log-maxage" is set to 30 or as appropriate
for command in container.command:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to check if all the containers in the pod has the flag enabled.

if command.startswith("--audit-log-maxage"):
if int(
command.split("=")[1]
) == apiserver_client.audit_config.get("audit_log_maxage", 30):
audit_log_maxage_set = True
break
if not audit_log_maxage_set:
break

if not audit_log_maxage_set:
report.status = "FAIL"
report.status_extended = f"Audit log max age is not set to 30 or as appropriate in pod {pod.name}."

findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_audit_log_maxbackup_set",
"CheckTitle": "Ensure that the --audit-log-maxbackup argument is set to 10 or as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Auditing",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with an appropriate number of audit log backups. Setting --audit-log-maxbackup to 10 or as per business requirements helps maintain a sufficient log backup for investigations or analysis.",
"Risk": "Without an adequate number of audit log backups, there may be insufficient log history to investigate past events or security incidents.",
"RelatedUrl": "https://kubernetes.io/docs/concepts/cluster-administration/audit/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to set the --audit-log-maxbackup argument to 10 or an appropriate number. Example: --audit-log-maxbackup=10",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure the API server audit log backup retention to 10 or as per your organization's requirements.",
"Url": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"
}
},
"Categories": [
"Logging",
"Compliance"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Ensure the audit log backup retention period is set appropriately to balance between storage constraints and the need for historical data."
}
@@ -0,0 +1,38 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)


class apiserver_audit_log_maxbackup_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"Audit log max backup is set appropriately in the API server in pod {pod.name}."
audit_log_maxbackup_set = False
for container in pod.containers.values():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to check if all the containers in the pod has the flag enabled.

audit_log_maxbackup_set = False
# Check if "--audit-log-maxbackup" is set to 10 or as appropriate
for command in container.command:
if command.startswith("--audit-log-maxbackup"):
if int(
command.split("=")[1]
) == apiserver_client.audit_config.get(
"audit_log_maxbackup", 10
):
audit_log_maxbackup_set = True
break
if not audit_log_maxbackup_set:
break

if not audit_log_maxbackup_set:
report.status = "FAIL"
report.status_extended = f"Audit log max backup is not set to 10 or as appropriate in pod {pod.name}."

findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_audit_log_maxsize_set",
"CheckTitle": "Ensure that the --audit-log-maxsize argument is set to 100 or as appropriate",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Auditing",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "KubernetesAPIServer",
"Description": "This check ensures that the Kubernetes API server is configured with an appropriate audit log file size limit. Setting --audit-log-maxsize to 100 MB or as per business requirements helps manage the size of log files and prevents them from growing excessively large.",
"Risk": "Without an appropriate audit log file size limit, log files can grow excessively large, potentially leading to storage issues and difficulty in log analysis.",
"RelatedUrl": "https://kubernetes.io/docs/concepts/cluster-administration/audit/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to set the --audit-log-maxsize argument to 100 MB or an appropriate size. Example: --audit-log-maxsize=100",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Configure the API server audit log file size limit to 100 MB or as per your organization's requirements.",
"Url": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"
}
},
"Categories": [
"Logging",
"Compliance"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Adjust the audit log file size limit based on your organization's storage capabilities and logging requirements."
}
@@ -0,0 +1,38 @@
from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
apiserver_client,
)


class apiserver_audit_log_maxsize_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"Audit log max size is set appropriately in the API server in pod {pod.name}."
audit_log_maxsize_set = False
for container in pod.containers.values():
audit_log_maxsize_set = False
# Check if "--audit-log-maxsize" is set to 100 MB or as appropriate
for command in container.command:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to check if all the containers in the pod has the flag enabled.

if command.startswith("--audit-log-maxsize"):
if int(
command.split("=")[1]
) == apiserver_client.audit_config.get(
"audit_log_maxsize", 100
):
audit_log_maxsize_set = True
break
if not audit_log_maxsize_set:
break

if not audit_log_maxsize_set:
report.status = "FAIL"
report.status_extended = f"Audit log max size is not set to 100 MB or as appropriate in pod {pod.name}."

findings.append(report)
return findings
@@ -0,0 +1,36 @@
{
"Provider": "kubernetes",
"CheckID": "apiserver_audit_log_path_set",
"CheckTitle": "Ensure that the --audit-log-path argument is set",
"CheckType": [
"Security",
"Configuration"
],
"ServiceName": "apiserver",
"SubServiceName": "Auditing",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "KubernetesAPIServer",
"Description": "This check verifies that the Kubernetes API server is configured with an audit log path. Enabling audit logs helps in maintaining a chronological record of all activities and operations which can be critical for security analysis and troubleshooting.",
"Risk": "Without audit logs, it becomes difficult to track changes and activities within the cluster, potentially obscuring the detection of malicious activities or operational issues.",
"RelatedUrl": "https://kubernetes.io/docs/concepts/cluster-administration/audit/",
"Remediation": {
"Code": {
"CLI": "Edit the kube-apiserver configuration to set the --audit-log-path argument to a valid log path. Example: --audit-log-path=/var/log/apiserver/audit.log",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable audit logging in the API server by specifying a valid path for --audit-log-path to ensure comprehensive activity logging within the cluster.",
"Url": "https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"
}
},
"Categories": [
"Logging",
"Compliance"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Audit logs are not enabled by default in Kubernetes. Configuring them is essential for security monitoring and forensic analysis."
}
@@ -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_audit_log_path_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"Audit log path is set in the API server in pod {pod.name}."
)
audit_log_path_set = False
for container in pod.containers.values():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to check if all the containers in the pod has the flag enabled.

audit_log_path_set = False
# 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

if not audit_log_path_set:
report.status = "FAIL"
report.status_extended = f"Audit log path is not set in pod {pod.name}."

findings.append(report)
return findings