Merge pull request #90 from aquasecurity/detect-api-server

Only report API Servers that behave like Kubernetes API Servers
This commit is contained in:
Liz Rice
2019-02-25 17:57:18 +00:00
committed by GitHub
5 changed files with 41 additions and 10 deletions

View File

@@ -12,17 +12,19 @@ class ApiServer(Service, Event):
Service.__init__(self, name="API Server")
# Other devices could have this port open, but we can check to see if it looks like a Kubernetes node
# A Kubernetes API server will respond with a JSON message that includes a "code" field for the HTTP status code
@handler.subscribe(OpenPortEvent, predicate=lambda x: x.port==443 or x.port==6443)
class ApiServerDiscovery(Hunter):
"""Api Server Discovery
Checks for the existence of a an Api Server
Checks for the existence of a an API Server
"""
def __init__(self, event):
self.event = event
def execute(self):
logging.debug("Attempting to discover an Api server")
logging.debug("Attempting to discover an API server")
main_request = requests.get("https://{}:{}".format(self.event.host, self.event.port), verify=False).text
if "code" in main_request:
if '"code"' in main_request:
self.event.role = "Master"
self.publish_event(ApiServer())
self.publish_event(ApiServer())

View File

@@ -24,12 +24,12 @@ class RunningAsPodEvent(Event):
def get_auth_token(self):
try:
with open("/run/secrets/kubernetes.io/serviceaccount/token") as token_file:
with open("/var/run/secrets/kubernetes.io/serviceaccount/token") as token_file:
return token_file.read()
except IOError:
pass
def get_client_cert(self):
return "/run/secrets/kubernetes.io/serviceaccount/ca.crt"
return "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
class AzureMetadataApi(Vulnerability, Event):
"""Access to the Azure Metadata API exposes information about the machines associated with the cluster"""

View File

@@ -0,0 +1,27 @@
import requests_mock
from apiserver import ApiServer, ApiServerDiscovery
from ...core.events.types import Event
from ...core.events import handler
def test_ApiServer():
with requests_mock.Mocker() as m:
m.get('https://mockOther:443', text='elephant')
m.get('https://mockKubernetes:443', text='{"code":403}')
e = Event()
e.port = 443
e.host = 'mockOther'
a = ApiServerDiscovery(e)
a.execute()
e.host = 'mockKubernetes'
a.execute()
# We should only generate an ApiServer event for a response that looks like it came from a Kubernetes node
@handler.subscribe(ApiServer)
class testApiServer(object):
def __init__(self, event):
assert event.host == 'mockKubernetes'

View File

@@ -5,7 +5,8 @@ import uuid
import ast
from ...core.events import handler
from ...core.events.types import Vulnerability, Event, OpenPortEvent
from ...core.events.types import Vulnerability, Event
from ..discovery.apiserver import ApiServer
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure, PrivilegeEscalation
""" Vulnerabilities """
@@ -17,7 +18,7 @@ class ServerApiVersionEndPointAccess(Vulnerability, Event):
self.evidence = evidence
# Passive Hunter
@handler.subscribe(OpenPortEvent, predicate=lambda x: x.port == 443 or x.port == 6443)
@handler.subscribe(ApiServer)
class IsVulnerableToCVEAttack(Hunter):
""" Node is running a Kubernetes version vulnerable to critical CVE-2018-1002105 """

View File

@@ -4,7 +4,8 @@ import requests
import uuid
from ...core.events import handler
from ...core.events.types import Vulnerability, Event, OpenPortEvent
from ...core.events.types import Vulnerability, Event
from ..discovery.apiserver import ApiServer
from ...core.types import Hunter, ActiveHunter, KubernetesCluster, RemoteCodeExec, AccessRisk, InformationDisclosure
@@ -203,7 +204,7 @@ class ApiServerPassiveHunterFinished(Event):
# Passive Hunter
@handler.subscribe(OpenPortEvent, predicate=lambda x: x.port == 443 or x.port == 6443)
@handler.subscribe(ApiServer)
class AccessApiServerViaServiceAccountToken(Hunter):
""" API Server Hunter
Accessing the API server within a compromised pod might grant an attacker full control over the cluster