Skip to content

Instantly share code, notes, and snippets.

@gjyoung1974
Last active January 6, 2024 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gjyoung1974/3d4ff6bce43b286028d7749512bce87a to your computer and use it in GitHub Desktop.
Save gjyoung1974/3d4ff6bce43b286028d7749512bce87a to your computer and use it in GitHub Desktop.
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