Skip to content

Commit

Permalink
Merge branch 'main' into trivy-template
Browse files Browse the repository at this point in the history
  • Loading branch information
krol3 authored Sep 25, 2022
2 parents b60bedc + b32011f commit a43985c
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish-chart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
with:
fetch-depth: 0
- name: Setup Kubernetes cluster (KIND)
uses: helm/kind-action@d08cf6ff1575077dee99962540d77ce91c62387d
uses: helm/kind-action@9e8295d178de23cbfbd8fa16cf844eec1d773a07
with:
version: ${{ env.KIND_VERSION }}
image: ${{ env.KIND_IMAGE }}
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
[![Go Report Card][report-card-img]][report-card]
![](https://github.com/aquasecurity/postee/workflows/Go/badge.svg)
[![License][license-img]][license]
<a href="https://slack.aquasec.com/?_ga=2.51428586.2119512742.1655808394-1739877964.1641199050">
<img src="https://img.shields.io/static/v1?label=Slack&message=Join+our+Community&color=4a154b&logo=slack">
</a>


[download]: https://img.shields.io/github/downloads/aquasecurity/postee/total?logo=github
Expand Down
2 changes: 1 addition & 1 deletion deploy/helm/postee/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: A Helm chart for Postee
type: application

# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.4.2
version: 0.4.3

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
Expand Down
1 change: 0 additions & 1 deletion deploy/helm/postee/cfg-files/cfg.yaml

This file was deleted.

3 changes: 2 additions & 1 deletion deploy/helm/postee/templates/cfg-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ kind: ConfigMap
metadata:
name: {{ include "postee.fullname" . }}-cfg
data:
{{ (tpl (.Files.Glob .Values.posteeConfigPath).AsConfig . ) | indent 2 }}
cfg.yaml: |
{{ .Values.posteeConfig | indent 4 }}
151 changes: 150 additions & 1 deletion deploy/helm/postee/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,156 @@
# Declare variables to be passed into your templates.

replicaCount: 1
posteeConfigPath: "cfg-files/*"
posteeConfig: |
# The configuration file contains a general settings section,
# routes, templates and actions sections.
name: tenant # The tenant name
aqua-server: # URL of Aqua Server for links. E.g. https://myserver.aquasec.com
max-db-size: 1000MB # Max size of DB. <numbers><unit suffix> pattern is used, such as "300MB" or "1GB". If empty or 0 then unlimited
db-verify-interval: 1 # How often to check the DB size. By default, Postee checks every 1 hour
# Routes are used to define how to handle an incoming message
routes:
- name: stdout
actions: [ stdout ]
template: raw-json
#- name: route1 # Route name. Must be unique
# input: contains(input.image, "alpine") # REGO rule to match input message against route
# input-files: # Array filePaths to files with REGO rules
# - Allow-Image-Name.rego
# - Ignore-Image-Name.rego
# - Allow-Registry.rego
# - Ignore-Registry.rego
# - Policy-Only-Fix-Available.rego
# - Policy-Min-Vulnerability.rego
# - Policy-Related-Features.rego
# actions: [my-slack] # Action name (needs to be defined under "actions") which will receive the message
# template: slack-template # Template name (needs to be defined under "templates") which will be used to process the message output format
# plugins: # Optional plugins
# aggregate-message-number: # Number of same messages to aggregate into one output message
# aggregate-message-timeout: # Number of seconds/minutes/hours to aggregate same messages into one output. Maximum is 24 hours. Use Xs or Xm or Xh
# unique-message-props: ["digest","image","registry", "vulnerability_summary.high", "vulnerability_summary.medium", "vulnerability_summary.low"] # Optional: Comma separated list of top level properties which uniqult identifies an event message. If message with same property values is received more than once it will be ignored
# unique-message-timeout: # Number of seconds/minutes/hours/days before expiring of a message. Expired messages are removed from db. If option is empty message is never deleted
# Templates are used to format a message
templates:
- name: vuls-slack # Out of the box template for slack
rego-package: postee.vuls.slack # Slack template REGO package (available out of the box)
- name: vuls-html # Out of the box HTML template
rego-package: postee.vuls.html # HTML template REGO package (available out of the box)
- name: raw-html # Raw message json
rego-package: postee.rawmessage.html # HTML template REGO package (available out of the box)
- name: legacy # Out of the box legacy Golang template
legacy-scan-renderer: html
- name: legacy-slack # Legacy slack template implemented in Golang
legacy-scan-renderer: slack
- name: legacy-jira # Legacy jira template implemented in Golang
legacy-scan-renderer: jira
- name: custom-email # Example of how to use a template from a Web URL
url: # URL to custom REGO file
- name: raw-json # route message "As Is" to external webhook
rego-package: postee.rawmessage.json
- name: vuls-cyclonedx # export vulnerabilities to CycloneDX XML
rego-package: postee.vuls.cyclondx
# Rules are predefined rego policies that can be used to trigger routes
rules:
- name: Initial Access
- name: Credential Access
- name: Privilege Escalation
- name: Defense Evasion
- name: Persistence
# Actions are target services that should consume the messages
actions:
- name: stdout
type: stdout
enable: true
- name: my-jira # name must be unique
type: jira # supported types: jira, email
enable: false
url: # Mandatory. E.g "https://johndoe.atlassian.net"
user: # Mandatory. E.g :johndoe@gmail.com"
password: # Optional. Specify Jira user API key. Used only for Jira Cloud
token: # Optional. Specify Jira user Personal Access Token. Used only for Jira Server/Data Center
project-key: # Mandatory. Specify the JIRA product key
tls-verify: false
board: # Optional. Specify the Jira board name to open tickets on
labels: # Optional, specify array of labels to add to Ticket, for example: ["label1", "label2"]
issuetype: # Optional. Specifty the issue type to open (Bug, Task, etc.). Default is "Task"
priority: # Optional. Specify the issues severity. Default is "High"
assignee: # Optional. Specify the assigned user. Default is the user that opened the ticket
- name: my-email
type: email
enable: false
user: # Optional (if auth supported): SMTP user name (e.g. johndoe@gmail.com)
password: # Optional (if auth supported): SMTP password
host: # Mandatory: SMTP host name (e.g. smtp.gmail.com)
port: # Mandatory: SMTP server port (e.g. 587)
sender: # Mandatory: The email address to use as a sender
recipients: ["", ""] # Mandatory: comma separated list of recipients
- name: my-email-smtp-server
type: email
enable: false
use-mx: true
sender: # Mandatory: The email address to use as a sender
recipients: ["", ""] # Mandatory: comma separated list of recipients
- name: my-slack
type: slack
enable: false
url: https://hooks.slack.com/services/TAAAA/BBB/<key>
- name: ms-team
type: teams
enable: false
url: https://outlook.office.com/webhook/.... # Webhook's url
- name: webhook
type: webhook
enable: false
url: https://..../webhook/ # Webhook's url
timeout: # Webhook's timeout. <numbers><unit suffix> pattern is used, such as "300ms" or "2h45m". Default: 120s
- name: splunk
type: splunk
enable: false
url: http://localhost:8088 # Mandatory. Url of a Splunk server
token: <token> # Mandatory. a HTTP Event Collector Token
size-limit: 10000 # Optional. Maximum scan length, in bytes. Default: 10000
- name: my-servicenow
type: serviceNow
enable: false
user: # Mandatory. E.g :johndoe@gmail.com"
password: # Mandatory. Specify user API key
instance: # Mandatory. Name of ServiceN ow Instance
board: # Specify the ServiceNow board name to open tickets on. Default is "incident"
- name: my-nexus-iq
type: nexusIq
enable: false
user: # Mandatory. User name
password: # Mandatory. User password
url: # Mandatory. Url of Nexus IQ server
organization-id: # Mandatory. Organization UID like "222de33e8005408a844c12eab952c9b0"
- name: my-opsgenie
type: opsgenie
enable: false
token: <API Key> # Mandatory. an API key from an API integration
user: # Optional. Display name of the request owner.
assignee: # Optional. Comma separated list of users that the alert will be routed to send notifications
recipients: [""] # Optional. Comma separated list of users that the alert will become visible to without sending any notification
tags: # Optional. Comma separated list of the alert tags.
priority: # Optional. Specify the alert priority. Default is "P3"
alias: # Optional. Client-defined identifier of the alert.
entity: # Optional. Entity field of the alert that is generally used to specify which domain alert is related to.
posteUi:
port: 8000
Expand Down
Binary file added docs/img/postee-ui-drag-and-drop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions docs/improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Improvements

Postee like any other software isn't perfect and as the writing of this document can be improved in the following areas:

## UI

This is an improvement that would benefit not just new users of Postee but also add ease of use for existing users to configure Postee on the fly with drag and drop-'ing of components to configure Postee.

![img.png](img/postee-ui-drag-and-drop.png)

The above is an example of a User Interface that Postee could have where the blocks (Trivy, AWS Security Hub and Slack) are dragged and dropped into the view and connected as needed. This would translate into a Postee configuration file being written to disk.


## Alternate Policy language

Today Postee supports Rego as the primary language for policy evaluation. While Rego is purposely suited for being a policy language, it might be challenging to learn for new users and feel comfortable in.

Therefore, having an alternate policy language to write rules could benefit with Postee adoption even further. A few ideas that we've experimented in some of our other projects are as follows:

1. Golang Policies
2. [CEL-Go](https://github.com/google/cel-go)

## Support for more Actions

Today Postee supports a wide variety of Postee Actions but the list can be further expanded by including the following:

1. AWS Cloudwatch Logs
2. Azure automation
3. GCP automation

Extending Postee to support a new Action is very simple. You can take a look at this PR to see exactly which places you'll need to modify in order to support a new Action.

[Link to example PR](https://github.com/aquasecurity/postee/pull/468)


## My idea is not listed here
Do you have an idea that you'd like to implement in Postee? Reach out to us via GitHub Issues or on Slack to discuss more about it.
158 changes: 158 additions & 0 deletions rego-templates/trivy-jira.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package postee.vuls.html
############################################# Common functions ############################################
with_default(obj, prop, default_value) = default_value {
not obj[prop]
}

with_default(obj, prop, default_value) = obj[prop] {
obj[prop]
}

#import common.by_flag
################################################ Templates ################################################
#main template to render message

tpl:=`
h1. Image name: %s
%s
%s
%s
%s
%s
`

vlnrb_tpl = `
h4. %s severity vulnerabilities
%s
`
#Extra % is required in width:100%

table_tpl := `
%s
`

cell_tpl := `| %s `

header_tpl := `|| %s `

row_tpl := `
| %s `

colored_text_tpl := "{color:%s}%s{color}"

###########################################################################################################

############################################## Html rendering #############################################

render_table_headers(headers) = row {
count(headers) > 0
ths := [th |
header := headers[_]
th := sprintf(header_tpl, [header])
]

row := sprintf(row_tpl, [concat("", ths)])
}

render_table_headers(headers) = "" { #if headers not specified return empty results
count(headers) == 0
}

render_table(headers, content_array) = s {
rows := [tr |
cells := content_array[_]
tds := [td |
ctext := cells[_]
td := to_cell(ctext)
]

tr = sprintf(row_tpl, [concat("", tds)])
]

s := sprintf(table_tpl, [concat("", array.concat([render_table_headers(headers)], rows))])
}

## why I added it?
to_cell(txt) = c {
c := sprintf(cell_tpl, [txt])
}

to_colored_text(color, txt) = spn {
spn := sprintf(colored_text_tpl, [color, txt])
}

####################################### Template specific functions #######################################
to_severity_color(color, level) = spn {
spn := to_colored_text(color, format_int(with_default(input.Metadata.vulnerability_summary, level, 0), 10))
}

cnt_by_severity(severity) = cnt {
vln_list := [r |
some i, j
item := input.Results[i]

item.Vulnerabilities[j].Severity == severity

r := item.Vulnerabilities[j]
]

cnt := count(vln_list)
}

# 2 dimension array for vulnerabilities summary
severities_stats := [
["critical", to_severity_color("#c00000", "critical")],
["high", to_severity_color("#e0443d", "high")],
["medium", to_severity_color("#f79421", "medium")],
["low", to_severity_color("#e1c930", "low")],
["negligible", to_severity_color("green", "negligible")],
]

vlnrb_headers := ["Layer", "Title","Vulnerability ID", "Resource name", "Path", "Installed version", "Fix version", "Url"]

render_vlnrb(severity, list) = sprintf(vlnrb_tpl, [severity, render_table(vlnrb_headers, list)]) {
count(list) > 0
}

render_vlnrb(severity, list) = "" { #returns empty string if list of vulnerabilities is passed
count(list) == 0
}

# builds 2-dimension array for vulnerability table
vln_list(severity) = vlnrb {
some i, j
vlnrb := [r |
item := input.Results[i]

target := item.Target
vlnname := item.Vulnerabilities[j].VulnerabilityID
title := item.Vulnerabilities[j].Title
fxvrsn := with_default(item.Vulnerabilities[j], "FixedVersion", "none")
resource_name = with_default(item.Vulnerabilities[j], "PkgName", "none")
resource_path = with_default(item.Vulnerabilities[j], "PkgPath", "none")
resource_version = with_default(item.Vulnerabilities[j], "InstalledVersion", "none")
primaryurl = with_default(item.Vulnerabilities[j], "PrimaryURL", "none")
references = with_default(item.Vulnerabilities[j], "References", "none")

item.Vulnerabilities[j].Severity == severity # only items with severity matched
r := [target, title, vlnname, resource_name, resource_path, resource_version, fxvrsn, primaryurl]
]
}

###########################################################################################################

title = sprintf("%s vulnerability scan report", [input.ArtifactName])

aggregation_pkg := "postee.vuls.slack.trivy.aggregation"

result = msg {

msg := sprintf(tpl, [
input.ArtifactName,
render_vlnrb("Critical", vln_list("CRITICAL")),
render_vlnrb("High", vln_list("HIGH")),
render_vlnrb("Medium", vln_list("MEDIUM")),
render_vlnrb("Low", vln_list("LOW")),
render_vlnrb("Negligible", vln_list("NEGLIGIBLE"))
])
}

0 comments on commit a43985c

Please sign in to comment.