Last active
January 6, 2024 00:46
-
-
Save gjyoung1974/3d4ff6bce43b286028d7749512bce87a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import subprocess | |
import docker | |
from kubernetes import client, config | |
from tenable.cs import ContainerSecurity | |
from jira import JIRA | |
dockerClient = docker.from_env() | |
config.load_kube_config() | |
v1 = client.CoreV1Api() | |
# Get podSpec so we can use the data | |
def get_pod_details(): | |
images = [] | |
for pod in v1.list_pod_for_all_namespaces().items: | |
images.append(pod.metadata.namespace + "," + pod.spec.containers[0].image) | |
for image in images: | |
print(image) | |
# Pull down the images running on production and scan with Tenable Container Security Tenable.SC | |
def vuln_scan_containers(tio_access_key, tio_secret_key): | |
rows = [] | |
# skip some namespaces | |
for i in v1.list_pod_for_all_namespaces().items: | |
if i.metadata.namespace != "default": | |
if i.metadata.namespace != "kube-node-lease": | |
if i.metadata.namespace != "kube-public ": | |
if i.metadata.namespace != "kube-system ": | |
if i.metadata.namespace != "monitoring": | |
if i.metadata.namespace != "security": | |
rows.append(str(i.spec.containers[0].image)) | |
rows = list(dict.fromkeys(rows)) | |
print("Adding " + str(len(rows)) + " total # of images.") | |
for image in rows: | |
print("Adding image: " + image) | |
for image in rows: | |
# print(image) | |
# pull down each image, save each image and pipe the tar.gz stream to the Tenable.CS cs-scanner container | |
cmd = 'docker pull ' + image + ' && docker save ' + image + ' | docker run ' \ | |
'-e TENABLE_ACCESS_KEY="' + tio_access_key + '" -e ' \ | |
'TENABLE_SECRET_KEY="' + tio_secret_key + '" -e ' \ | |
'IMPORT_REPO_NAME="' + 'pm' + '" -i tenableio-docker-consec-local.jfrog.io/cs-scanner:latest ' \ | |
'inspect-image "' + image + '"' | |
process = subprocess.Popen( | |
cmd, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
shell=True) | |
stdout, stderr = process.communicate() | |
stdout, stderr | |
result = stdout | |
print(result) | |
# Scan containers for embedded malware, viruses, potential unwanted programs, etc.. | |
def malware_scan_containers(): | |
print('foo') | |
# TODO: Add a mal-ware scanner | |
# Create 1 Jira issue per container image tag + attach sub-tasks per each vulnerability finding | |
def create_jira_issues(tio_access_key, tio_secret_key, jira_user, jira_api_key, jira_server_url, project_name): | |
# Tenable Container Security API Client | |
cs = ContainerSecurity(access_key="" + tio_access_key + "", secret_key="" + tio_secret_key + "") | |
# Jira API Client | |
jira = JIRA(basic_auth=('' + jira_user + '', '' + jira_api_key + ''), | |
options={'server': '' + jira_server_url + ''}) | |
vulnerabilities = [] | |
for image in cs.images.list(limit=500): | |
if int(image['score']) >= 4: | |
digest = str(image['digest']) | |
report = cs.reports.report(digest) | |
for finding in report['findings']: | |
# If CVSS is medium or above: | |
if float(finding['nvdFinding']['cvss_score']) >= 4.0: | |
vulnerabilities.append(finding) | |
# Get the namespace team for the image from k8s | |
# TODO how to inject the namespace at the beginning of the finding | |
for vuln in vulnerabilities: | |
# Create a Jira Issue object | |
issue_dict = { | |
'project': {'id': 14673}, | |
'summary': '' + | |
# use repository/image-name:image-tag as the issue title | |
str(image['repoName'][3:]) + "/" + str(image['name']) + ":" + str(image['tag']) + | |
' requires security patches', | |
'description': 'Image: ' + | |
str(image['repoName'] + '/' + str(image['name']) + ":" + str(image['tag'])) + | |
' requires security patches. See this Jira\'s sub-tasks for individual bugs to fix/close.', | |
'issuetype': {'name': 'Bug'} | |
} | |
# TODO add a tag to the Tenable issue to indicate we've added the issue to Jira | |
# TODO if the issue exists in Jira, just update the issue data | |
new_issue = jira.create_issue(fields=issue_dict) | |
print(str(image['repoName'][3:]) + ' contains: ' + str(vuln['nvdFinding']['cve'])) | |
# major todo | |
# TODO make sure there are mappings between pods and JIRA group IDs (assign to group vs indiv) | |
# how to add the Assignee in GDPR mode | |
# assignee = {"id": '5d00dcc392e6c70c5349a11d'} | |
# jira.assign_issue(new_issue.id, assignee) | |
for finding in vulnerabilities: | |
issue_subtask = { | |
# Place the Security team's project | |
'project': {'key': '' + project_name + ''}, | |
# Put the CVE ID and repo/image:tag as the sub_task's title | |
'summary': str(finding['nvdFinding']['cve']) + ': ' + str(image['repoName'][3:]) | |
+ "/" + str(image['name']) + ":" + str(image['tag']), | |
# Give the sub_task owner's assignee prescribtive guidance about evaluationg and resolving | |
'description': 'Remediate the following security bug(s): ' + | |
finding['nvdFinding']['description'] + ", " + | |
finding['nvdFinding']['remediation'] + ' in the docker container image: ' + | |
# Add the image as a URL so the user can view he details in the cloud console | |
'https://' + str(image['repoName'][3:]) + "/" + str(image['name']) + ":" + str(image['tag']) + | |
'. Evaluate and apply the recommended remediation/or updated packages listed' | |
' in this sub_task\'s comments.', | |
# Attach each finding and recommended resolution as a sub task | |
'issuetype': {'name': 'Sub-task'}, | |
'parent': {'id': new_issue.id}, | |
} | |
try: | |
# Add a sub_task per finding per vulnerable image | |
sub_task = jira.create_issue(fields=issue_subtask) | |
# TODO: why are only some of these working | |
# Add the image tag to sub task | |
jira.add_comment(sub_task, 'Image Tag: https://' + str(image['repoName'][3:]) | |
+ "/" + str(image['name']) + ":" + str(image['tag'])) | |
# Add remediation guidance to the sub task as a comment | |
jira.add_comment(sub_task, 'Guidance: ' + str(vuln['nvdFinding']['remediation'])) | |
# Add affected packages to the sub task as a comment | |
for package in vuln['packages']: | |
jira.add_comment(sub_task, 'Affected package: ' + str(package)) | |
# Add vendor disclosure references to sub task as a comment | |
reference_urls='' | |
for reference in vuln['nvdFinding']['references']: | |
reference_urls += str(reference + "\n") | |
# add reference URLs to a single comment | |
jira.add_comment(sub_task, 'References: ' + str(reference_urls)) | |
except Exception as e: | |
print(str(e.__cause__), str(e)) | |
pass | |
print('issue: ' + new_issue.key + ' created') | |
def main(): | |
# Tenable and Jira credentials | |
# TODO vault these create | |
tio_access_key = '' | |
tio_secret_key = '' | |
jira_user = 'gordon.young@example.com' | |
jira_api_key = '' | |
jira_server_url = 'https://example.atlassian.net' | |
jira_project = 'SECPROJECT' | |
# Scan all of our containers | |
vuln_scan_containers(tio_access_key, tio_secret_key) | |
# Create all of our Jira issues | |
create_jira_issues(tio_access_key, tio_secret_key, jira_user, jira_api_key, jira_server_url, jira_project) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment