├── .github
└── workflows
│ ├── add-issue-to-triage.yml
│ └── add-new-pr-to-oss-triaging.yml
├── .gitignore
├── .gitmodules
├── Readme.md
├── acs-export-example
├── .gitignore
├── cmd
│ └── root.go
├── demo.tape
├── go.mod
├── go.sum
├── main.go
├── pkg
│ ├── config
│ │ └── config.go
│ ├── csv
│ │ └── csv.go
│ ├── export
│ │ └── export.go
│ ├── filter
│ │ └── filter.go
│ └── table
│ │ └── table.go
└── readme.md
├── api-examples
├── README.md
├── authprovider-minrole.md
├── delete_group.md
├── groupsbatch_newgroups.md
├── groupservice_creategroup.md
└── simple-alerts.md
├── backups
├── api-key-secret.yaml
├── cron-backup.yaml
├── cron-clean-backup.yaml
├── readme.md
└── retrieve-backups-pod.yaml
├── ci
├── Azure DevOps
│ └── Pipelines
│ │ ├── README.md
│ │ └── azure-pipelines.yml
├── CircleCI
│ ├── .circleci
│ │ └── config.yml
│ ├── README.md
│ └── deploy.yml
├── GitHub
│ ├── kube-linter
│ │ ├── .github
│ │ │ ├── actions
│ │ │ │ └── kube-lint
│ │ │ │ │ └── action.yml
│ │ │ └── workflows
│ │ │ │ └── kube-linter.yml
│ │ ├── .kube-linter
│ │ │ └── config.yaml
│ │ ├── README.md
│ │ └── yamls
│ │ │ └── deploy.yaml
│ └── stackrox-action
│ │ ├── .github
│ │ ├── actions
│ │ │ ├── stackrox-check
│ │ │ │ └── action.yml
│ │ │ └── stackrox-scan
│ │ │ │ └── action.yml
│ │ └── workflows
│ │ │ └── main.yml
│ │ └── README.md
├── GitLab
│ ├── .gitlab-ci.yml
│ └── README.md
├── Tekton
│ ├── README.md
│ ├── Sample
│ │ ├── rox-pipeline.yml
│ │ └── rox-secrets.yml
│ └── Tasks
│ │ ├── rox-deployment-check-task.yml
│ │ ├── rox-image-check-task.yml
│ │ └── rox-image-scan-task.yml
├── argo
│ ├── README.md
│ └── argo.yml
└── function
│ └── Google Function
│ ├── CI integration sample
│ └── .circleci
│ │ └── config.yml
│ ├── README.md
│ └── roxctl_image_check
│ ├── main.py
│ └── requirements.txt
├── completions
└── fish
│ └── roxctl.fish
├── compliance
└── scan-compliance.sh
├── guides
└── cloud-provider-integrations
│ └── azure-service-principal-m2m-auth.md
├── ingress
├── contour
│ └── central-ingress.yaml
├── haproxy
│ ├── Readme.md
│ ├── central-hap-ingress.yaml
│ └── haproxy-controller.yaml
├── istio-gw
│ ├── Readme.md
│ └── central-istio-gw-passthrough.yaml
├── nginx
│ ├── Readme.md
│ ├── central-nginx-encrypt-ingress.yaml
│ └── central-nginx-passthrough-ingress.yaml
└── traefik
│ ├── Readme.md
│ └── central-traefik-ingress.yaml
├── policies
├── CVE-2021-4034-build-deploy.json
├── CVE-2021-44228-build-deploy.json
├── leaky-vessels.json
├── oc-debug-runtime.json
├── polkit-execution.json
└── polkit-in-image.json
├── terraform
└── azure-sentinel
│ ├── README.md
│ ├── main.tf
│ ├── provider.tf
│ └── variables.tf
├── util-scripts
├── acs-correlation-example
│ ├── Dockerfile
│ ├── README.md
│ ├── acs_request.py
│ ├── app.py
│ ├── config.py
│ ├── endpoint_list.json
│ ├── logging.conf
│ ├── output
│ │ ├── sample_cluster_namespace_deployment_alert_output_file.json
│ │ └── sample_endpoint_policy_alert_count_output_file.json
│ └── requirements.txt
├── compliance-scans-classifications
│ ├── stackrox_classifications.sh
│ └── stackrox_compliance_scan.sh
├── component-details-to-csv
│ ├── README.md
│ └── component_details_csv.sh
├── cronjob-upload-vuln-definitions
│ ├── fetchvulns-cronjob.yaml
│ └── upload-vulns-configmap.yaml
├── export-all-policies
│ ├── README.md
│ └── export-all-policies.sh
├── export-cves-to-csv
│ ├── README.md
│ └── create-csv.sh
├── external-entities
│ ├── README.md
│ ├── external-entities.py
│ └── requirements.txt
├── generate_violations_csv
│ ├── README.md
│ ├── generate_violations_csv.py
│ └── requirements.txt
├── health-check
│ ├── README.md
│ └── health-check.sh
├── image-cve-report
│ ├── README.md
│ └── image-cve-report.sh
├── listening-endpoints
│ ├── README.md
│ └── listening-endpoints.sh
├── log4shell
│ ├── README.md
│ ├── log4shell-check.py
│ └── requirements.txt
├── policy-copy-all
│ ├── README.md
│ └── policy-copy-all.sh
├── policy-update
│ ├── README.md
│ └── policy-update.sh
├── policy-utils
│ └── policies-csv
│ │ ├── README.md
│ │ └── policies-csv.sh
├── rhcos-node-cves
│ ├── README.md
│ └── node-cve-report.sh
├── roxctl-base-image
│ ├── README.md
│ └── base.py
├── roxctl-grace-period
│ ├── README.md
│ └── grace.py
├── scan-all-registry-images
│ ├── README.md
│ └── ecr-scan-roxctl.sh
├── violations-to-csv
│ ├── README.md
│ └── violations-to-csv.sh
└── vuln-violation-details
│ └── vulnvdetails.sh
└── vulnerability-management
└── export-workloads
├── README.md
├── export-workloads.py
└── export-workloads.sh
/.github/workflows/add-issue-to-triage.yml:
--------------------------------------------------------------------------------
1 | name: Add any new issue to OSS Triaging project
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | add-to-project:
10 | name: Add issue to project
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/add-to-project@v0.3.0
14 | with:
15 | project-url: https://github.com/orgs/stackrox/projects/2
16 | github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }}
17 |
--------------------------------------------------------------------------------
/.github/workflows/add-new-pr-to-oss-triaging.yml:
--------------------------------------------------------------------------------
1 | name: Add any new Pull Request to OSS Triaging project
2 | on:
3 | pull_request_target:
4 | types: [opened, reopened]
5 |
6 | env:
7 | EXTERNAL_PR_LABEL: external-contributor
8 | PROJECT_URL: https://github.com/orgs/stackrox/projects/2 # OSS Triaging board
9 |
10 | jobs:
11 | check-pr-if-external:
12 | name: Add external label to pull request if outside StackRox
13 | runs-on: ubuntu-latest
14 | env:
15 | GH_TOKEN: ${{ github.token }}
16 | BASE_REPO: ${{ github.repository }}
17 | HEAD_REPO: ${{ github.event.pull_request.head.user.login }}/${{ github.event.pull_request.head.repo.name }}
18 | outputs:
19 | is_external_pr: ${{ steps.check-external-pr.outputs.is_external_pr }}
20 | steps:
21 | - name: Check out code
22 | uses: actions/checkout@v3
23 | - id: check-external-pr
24 | run: |
25 | set -uo pipefail
26 | if [[ $BASE_REPO != $HEAD_REPO ]]; then
27 | echo "::set-output name=is_external_pr::true"
28 | gh pr edit \
29 | ${{ github.event.pull_request.number }} \
30 | --add-label ${EXTERNAL_PR_LABEL}
31 | else
32 | echo "::set-output name=is_external_pr::false"
33 | fi
34 |
35 | add-to-project:
36 | name: Add pull request to project
37 | runs-on: ubuntu-latest
38 | needs: [check-pr-if-external]
39 | if: needs.check-pr-if-external.outputs.is_external_pr == 'true'
40 | steps:
41 | - uses: actions/add-to-project@v0.3.0
42 | with:
43 | project-url: ${{ env.PROJECT_URL }}
44 | github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }}
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Based on https://gist.github.com/octocat/9257657
2 |
3 | .idea
4 |
5 | # Compiled source #
6 | ###################
7 | *.com
8 | *.class
9 | *.dll
10 | *.exe
11 | *.o
12 | *.so
13 |
14 | # Packages #
15 | ############
16 | # it's better to unpack these files and commit the raw source
17 | # git has its own built in compression methods
18 | *.7z
19 | *.dmg
20 | *.gz
21 | *.iso
22 | *.jar
23 | *.rar
24 | *.tar
25 | *.zip
26 |
27 | # Logs and databases #
28 | ######################
29 | *.log
30 | *.sql
31 | *.sqlite
32 |
33 | # OS generated files #
34 | ######################
35 | .DS_Store
36 | .DS_Store?
37 | ._*
38 | .Spotlight-V100
39 | .Trashes
40 | ehthumbs.db
41 | Thumbs.db
42 |
43 | # Deployment #
44 | ##############
45 | sensor*.zip
46 | tmp
47 | /central-bundle
48 | /**/.terraform
49 | /terraform/**/.terraform.lock.hcl
50 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stackrox/contributions/b4cb0161e934907da97f96540e26cc85a89f385c/.gitmodules
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # StackRox community contributions
2 |
3 | Welcome to the StackRox contributions repository. This repository stores a variety of configuration files, scripts, and samples related to the deployment and use of the [StackRox Kubernetes security platform](https://www.stackrox.io) and [Red Hat Advanced Cluster Security](https://www.redhat.com/en/technologies/cloud-computing/openshift/advanced-cluster-security-kubernetes).
4 |
5 | All code in this repo is provided as-is without warranty or support from Red Hat.
6 |
7 | Join the #stackrox channel on [CNCF Slack](https://cncf.slack.com/) for community discussion and support.
8 |
9 | We'd love your feedback! Please take care with any of the configurations in this repo before applying using these in your environment.
10 |
11 | ## What's in this Repository
12 | * `ci/` samples for using StackRox *roxctl* command-line tool in CI/CD pipelines
13 | * `ingress/` configurations for StackRox under popular Kubernetes ingress controllers
14 | * `completions/` shell auto-completions for roxctl
15 | * `util-scripts/` scripts using Stackrox API or roxctl for popular tasks (export to csv,...)
16 | * `guides/` instructions on how to configure ACS or integrate it with 3rd party services
17 |
--------------------------------------------------------------------------------
/acs-export-example/.gitignore:
--------------------------------------------------------------------------------
1 | acs-export-example
2 | *.csv
3 |
--------------------------------------------------------------------------------
/acs-export-example/cmd/root.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "fmt"
7 | "os"
8 |
9 | "github.com/pkg/errors"
10 | "github.com/spf13/cobra"
11 |
12 | "github.com/stackrox/contributions/acs-export-example/pkg/config"
13 | "github.com/stackrox/contributions/acs-export-example/pkg/csv"
14 | "github.com/stackrox/contributions/acs-export-example/pkg/export"
15 | "github.com/stackrox/contributions/acs-export-example/pkg/filter"
16 | "github.com/stackrox/contributions/acs-export-example/pkg/table"
17 | )
18 |
19 | var cfg = config.ConfigType{}
20 | var stats = &config.Stats{}
21 |
22 | var rootCmd = &cobra.Command{
23 | Use: "acs-export-example",
24 | Short: "Use the ACS export APIs",
25 | Long: `CLI to browse data pulled from ACS (Advanced Cluster Security) (i.e. StackRox).`,
26 | Run: func(cmd *cobra.Command, args []string) {
27 | if err := validateFlags(); err != nil {
28 | fmt.Printf("%v\n", err)
29 | os.Exit(1)
30 | }
31 |
32 | ctx := context.Background()
33 |
34 | exporter, err := export.New(ctx, stats)
35 | if err != nil {
36 | panic(errors.Wrap(err, "could not create exporter"))
37 | }
38 |
39 | query := cfg.QueryFilter
40 |
41 | if cfg.FilterType == "server" {
42 | query = filter.BuildServerQuery(cfg)
43 | }
44 |
45 | os.Stderr.WriteString("Fetching deployments\n")
46 | deployments, err := exporter.GetDeployments(query)
47 | if err != nil {
48 | panic(errors.Wrap(err, "could not get deployments"))
49 | }
50 |
51 | os.Stderr.WriteString("Fetching images\n")
52 | images, err := exporter.GetImages(query)
53 | if err != nil {
54 | panic(errors.Wrap(err, "could not get images"))
55 | }
56 |
57 | if cfg.FilterType == "client" {
58 | deployments, images = filter.ClientFilter(deployments, images, cfg, stats)
59 | }
60 |
61 | // This runs for both client and server filtering because the server
62 | // doesn't filter out CVEs off of image scans that don't match the CVE filter
63 | deployments, images = filter.ClientVulnFilter(deployments, images, cfg, stats)
64 |
65 | if cfg.Output == "table" {
66 | if err = table.RenderTable(deployments, images); err != nil {
67 | panic(errors.Wrap(err, "Failed to render table"))
68 | }
69 | } else if cfg.Output == "csv" {
70 | if err = csv.RenderCsv(deployments, images); err != nil {
71 | panic(errors.Wrap(err, "Failed to render table"))
72 | }
73 | }
74 |
75 | if cfg.Stats {
76 | os.Stderr.WriteString(stats.String())
77 | }
78 | },
79 | }
80 |
81 | func Execute() {
82 | if err := rootCmd.Execute(); err != nil {
83 | fmt.Println(err)
84 | os.Exit(1)
85 | }
86 | }
87 |
88 | func contains(a []string, elem string) bool {
89 | for _, i := range a {
90 | if i == elem {
91 | return true
92 | }
93 | }
94 |
95 | return false
96 | }
97 |
98 | func quoteWrap(a []string) string {
99 | var buffer bytes.Buffer
100 |
101 | buffer.WriteString("[")
102 | for i, s := range a {
103 | buffer.WriteString(fmt.Sprintf("\"%s\"", s))
104 |
105 | if i < len(a)-1 {
106 | buffer.WriteString(", ")
107 | }
108 | }
109 | buffer.WriteString("]")
110 |
111 | return buffer.String()
112 | }
113 |
114 | func validateFlags() error {
115 | outputOptions := []string{"table", "csv"}
116 | filterTypeOptions := []string{"client", "server"}
117 | fixableOptions := []string{"true", "false", ""}
118 |
119 | if !contains(outputOptions, cfg.Output) {
120 | return errors.Errorf("Invalid value for --output=\"%s\". Available options: %v", cfg.Output, quoteWrap(outputOptions))
121 | }
122 |
123 | if !contains(filterTypeOptions, cfg.FilterType) {
124 | return errors.Errorf("Invalid value for --filter-type=\"%s\". Available options: %v", cfg.FilterType, quoteWrap(filterTypeOptions))
125 | }
126 |
127 | if !contains(fixableOptions, cfg.FixableFilter) {
128 | return errors.Errorf("Invalid value for --fixable=\"%s\". Available options: %v", cfg.FixableFilter, quoteWrap(fixableOptions))
129 | }
130 |
131 | if cfg.QueryFilter != "" && cfg.FilterType == "server" {
132 | return errors.New("Cannot supply a query filter when --filter-type=server")
133 | }
134 |
135 | return nil
136 | }
137 |
138 | func init() {
139 | rootCmd.PersistentFlags().StringVarP(&cfg.Output, "output", "o", "table", "Output format. Available options: [table, csv]")
140 | rootCmd.PersistentFlags().StringVarP(&cfg.NamespaceFilter, "namespace", "n", "", "Namespace client-side filter.")
141 | rootCmd.PersistentFlags().StringVarP(&cfg.ClusterFilter, "cluster", "c", "", "Cluster client-side filter.")
142 | rootCmd.PersistentFlags().StringVarP(&cfg.ImageNameFilter, "image", "i", "", "Image name client-side filter.")
143 | rootCmd.PersistentFlags().StringVarP(&cfg.VulnerabilityFilter, "vuln", "v", "", "Vulnerability client-side filter.")
144 | rootCmd.PersistentFlags().StringVarP(&cfg.QueryFilter, "query", "q", "", "Pass a query string to the server. Incompatible with --filter-type=server")
145 | rootCmd.PersistentFlags().StringVarP(&cfg.FixableFilter, "fixable", "f", "", "Filter on whether a cve is fixable. Available options: [true, false, \"\"].")
146 | rootCmd.PersistentFlags().StringVarP(&cfg.FilterType, "filter-type", "t", "client", "Where to do the param-based filtering. Available options: [client, server]")
147 | rootCmd.PersistentFlags().BoolVarP(&cfg.Stats, "stats", "s", false, "Print stats about the export")
148 | }
149 |
--------------------------------------------------------------------------------
/acs-export-example/demo.tape:
--------------------------------------------------------------------------------
1 | Output demo.gif
2 |
3 | Set FontSize 12
4 | Set Width 1600
5 | Set Height 700
6 |
7 | Type "./acs-export-example | head -n 38"
8 | Sleep 500ms
9 | Enter
10 | Sleep 15s
11 |
--------------------------------------------------------------------------------
/acs-export-example/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/stackrox/contributions/acs-export-example/cmd"
5 | )
6 |
7 | func main() {
8 | cmd.Execute()
9 | }
10 |
--------------------------------------------------------------------------------
/acs-export-example/pkg/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "time"
7 | )
8 |
9 | type ConfigType struct {
10 | Output string
11 | ClusterFilter string
12 | ImageNameFilter string
13 | NamespaceFilter string
14 | QueryFilter string
15 | VulnerabilityFilter string
16 | FixableFilter string
17 | FilterType string
18 | Stats bool
19 | }
20 |
21 | func (cfg *ConfigType) QueryStrings() map[string]string {
22 | ret := map[string]string{}
23 | ret["CLUSTER"] = "r/" + cfg.ClusterFilter
24 | ret["IMAGE"] = "r/" + cfg.ImageNameFilter
25 | ret["NAMESPACE"] = cfg.NamespaceFilter
26 | ret["CVE"] = "r/" + cfg.VulnerabilityFilter
27 | ret["FIXABLE"] = cfg.FixableFilter
28 | return ret
29 | }
30 |
31 | type Stats struct {
32 | ConnectDuration time.Duration
33 | DeploymentExportDuration time.Duration
34 | ImageExportDuration time.Duration
35 | DeploymentFilterDuration time.Duration
36 | ImageFilterDuration time.Duration
37 | DeploymentExportCount int
38 | ImageExportCount int
39 | FilteredDeploymentExportCount int
40 | FilteredImageExportCount int
41 | }
42 |
43 | func (s *Stats) String() string {
44 | var buffer bytes.Buffer
45 |
46 | buffer.WriteString("Durations:\n")
47 | buffer.WriteString(fmt.Sprintf(" Connect: %v\n", s.ConnectDuration))
48 | buffer.WriteString(fmt.Sprintf(" Deployment Export: %v \n", s.DeploymentExportDuration))
49 | buffer.WriteString(fmt.Sprintf(" Image Export: %v \n", s.ImageExportDuration))
50 | if s.DeploymentFilterDuration > 0 {
51 | buffer.WriteString(fmt.Sprintf(" Deployment Filtering: %v\n", s.DeploymentFilterDuration))
52 | }
53 | buffer.WriteString(fmt.Sprintf(" Image Filtering: %v \n", s.ImageFilterDuration))
54 | buffer.WriteString("\nCounts:\n")
55 | buffer.WriteString(fmt.Sprintf(" Deployments: %v \n", s.DeploymentExportCount))
56 | buffer.WriteString(fmt.Sprintf(" Images: %v \n", s.ImageExportCount))
57 | if s.DeploymentFilterDuration > 0 {
58 | buffer.WriteString(fmt.Sprintf(" Filtered Deployments: %v\n", s.FilteredDeploymentExportCount))
59 | }
60 | buffer.WriteString(fmt.Sprintf(" Filtered Images: %v \n", s.FilteredImageExportCount))
61 |
62 | return buffer.String()
63 | }
64 |
--------------------------------------------------------------------------------
/acs-export-example/pkg/csv/csv.go:
--------------------------------------------------------------------------------
1 | package csv
2 |
3 | import (
4 | "encoding/csv"
5 | "fmt"
6 | "os"
7 |
8 | storage "github.com/stackrox/rox/generated/storage"
9 | )
10 |
11 | func RenderCsv(deployments []*storage.Deployment, images []*storage.Image) error {
12 | imageMap := map[string]*storage.Image{}
13 |
14 | for _, image := range images {
15 | imageMap[image.Name.FullName] = image
16 | }
17 |
18 | writer := csv.NewWriter(os.Stdout)
19 | defer writer.Flush()
20 |
21 | headers := []string{"CVE", "Severity", "CVSS", "Status", "Component", "Fixed In", "Image", "Deployment", "Namespace", "Cluster"}
22 | writer.Write(headers)
23 |
24 | for _, d := range deployments {
25 | for _, container := range d.Containers {
26 | imageName := container.Image.Name.FullName
27 |
28 | image, found := imageMap[imageName]
29 | if !found || image.Scan == nil {
30 | continue
31 | }
32 |
33 | for _, component := range image.Scan.Components {
34 | for _, vuln := range component.Vulns {
35 | score := ""
36 | if vuln.CvssV3 != nil {
37 | score = fmt.Sprintf("v3: %.2f", vuln.CvssV3.Score)
38 | } else if vuln.CvssV2 != nil {
39 | score = fmt.Sprintf("v2: %.2f", vuln.CvssV2.Score)
40 | }
41 |
42 | status := ""
43 | if vuln.GetFixedBy() != "" {
44 | status = "fixable"
45 | }
46 |
47 | row := []string{vuln.Cve, vuln.Severity.String(), score, status, component.Name, vuln.GetFixedBy(), imageName, d.Name, d.Namespace, d.ClusterName}
48 | writer.Write(row)
49 | }
50 | }
51 | }
52 | }
53 |
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/acs-export-example/pkg/export/export.go:
--------------------------------------------------------------------------------
1 | package export
2 |
3 | import (
4 | "context"
5 | "io"
6 | "time"
7 |
8 | "github.com/pkg/errors"
9 | "google.golang.org/grpc"
10 |
11 | v1 "github.com/stackrox/rox/generated/api/v1"
12 | storage "github.com/stackrox/rox/generated/storage"
13 | "github.com/stackrox/rox/roxctl/common"
14 | "github.com/stackrox/rox/roxctl/common/auth"
15 | roxctlIO "github.com/stackrox/rox/roxctl/common/io"
16 | "github.com/stackrox/rox/roxctl/common/logger"
17 | "github.com/stackrox/rox/roxctl/common/printer"
18 |
19 | "github.com/stackrox/contributions/acs-export-example/pkg/config"
20 | )
21 |
22 | type Exporter struct {
23 | ctx context.Context
24 | conn *grpc.ClientConn
25 | stats *config.Stats
26 | }
27 |
28 | func New(ctx context.Context, stats *config.Stats) (Exporter, error) {
29 | defaultIO := roxctlIO.DefaultIO()
30 | start := time.Now()
31 | conn, err := common.GetGRPCConnection(auth.TokenAuth(), logger.NewLogger(defaultIO, printer.DefaultColorPrinter()))
32 | if err != nil {
33 | return Exporter{}, errors.Wrap(err, "could not establish gRPC connection to central")
34 | }
35 |
36 | stats.ConnectDuration = time.Now().Sub(start)
37 |
38 | return Exporter{
39 | ctx: ctx,
40 | conn: conn,
41 | stats: stats,
42 | }, nil
43 | }
44 |
45 | func (ex *Exporter) GetImages(query string) ([]*storage.Image, error) {
46 | svc := v1.NewImageServiceClient(ex.conn)
47 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
48 | defer cancel()
49 |
50 | start := time.Now()
51 | client, err := svc.ExportImages(ctx, &v1.ExportImageRequest{Query: query})
52 | if err != nil {
53 | return nil, errors.Wrap(err, "could not initialize stream client")
54 | }
55 |
56 | images := []*storage.Image{}
57 | for {
58 | image, err := client.Recv()
59 | if err != nil {
60 | if errors.Is(err, io.EOF) {
61 | break
62 | }
63 | return nil, errors.Wrap(err, "stream broken by unexpected error")
64 | }
65 |
66 | images = append(images, image.Image)
67 | }
68 |
69 | ex.stats.ImageExportDuration = time.Now().Sub(start)
70 | ex.stats.ImageExportCount = len(images)
71 |
72 | return images, nil
73 | }
74 |
75 | func (ex *Exporter) GetDeployments(query string) ([]*storage.Deployment, error) {
76 | svc := v1.NewDeploymentServiceClient(ex.conn)
77 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
78 | defer cancel()
79 |
80 | start := time.Now()
81 | client, err := svc.ExportDeployments(ctx, &v1.ExportDeploymentRequest{Query: query})
82 | if err != nil {
83 | return nil, errors.Wrap(err, "could not initialize stream client")
84 | }
85 |
86 | deployments := []*storage.Deployment{}
87 | for {
88 | deployment, err := client.Recv()
89 | if err != nil {
90 | if errors.Is(err, io.EOF) {
91 | break
92 | }
93 | return nil, errors.Wrap(err, "stream broken by unexpected error")
94 | }
95 |
96 | deployments = append(deployments, deployment.Deployment)
97 | }
98 |
99 | ex.stats.DeploymentExportDuration = time.Now().Sub(start)
100 | ex.stats.DeploymentExportCount = len(deployments)
101 |
102 | return deployments, nil
103 | }
104 |
--------------------------------------------------------------------------------
/acs-export-example/pkg/filter/filter.go:
--------------------------------------------------------------------------------
1 | package filter
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "os"
7 | "strings"
8 | "time"
9 |
10 | "github.com/stackrox/contributions/acs-export-example/pkg/config"
11 | storage "github.com/stackrox/rox/generated/storage"
12 | )
13 |
14 | func keepVulnBasedOnFixableFilter(vuln *storage.EmbeddedVulnerability, fixableFilter string) bool {
15 | if fixableFilter == "" {
16 | return true
17 | }
18 |
19 | fixable := "true"
20 |
21 | if vuln.GetFixedBy() == "" {
22 | fixable = "false"
23 | }
24 |
25 | return fixableFilter == fixable
26 | }
27 |
28 | func ClientVulnFilter(deployments []*storage.Deployment, images []*storage.Image, cfg config.ConfigType, stats *config.Stats) (filteredDeployments []*storage.Deployment, filteredImages []*storage.Image) {
29 | start := time.Now()
30 | for _, image := range images {
31 | vulnFound := false
32 | if image.Scan != nil {
33 | for _, component := range image.Scan.Components {
34 | vulnsToKeep := []*storage.EmbeddedVulnerability{}
35 | for _, vuln := range component.Vulns {
36 | if strings.Contains(vuln.Cve, cfg.VulnerabilityFilter) && keepVulnBasedOnFixableFilter(vuln, cfg.FixableFilter) {
37 | vulnFound = true
38 | vulnsToKeep = append(vulnsToKeep, vuln)
39 | }
40 | }
41 | component.Vulns = vulnsToKeep
42 | }
43 | }
44 |
45 | if vulnFound {
46 | filteredImages = append(filteredImages, image)
47 | }
48 | }
49 |
50 | stats.ImageFilterDuration = stats.ImageFilterDuration + (time.Now().Sub(start))
51 | stats.FilteredImageExportCount = len(filteredImages)
52 |
53 | filteredDeployments = deployments
54 | return
55 | }
56 |
57 | func ClientFilter(deployments []*storage.Deployment, images []*storage.Image, cfg config.ConfigType, stats *config.Stats) (filteredDeployments []*storage.Deployment, filteredImages []*storage.Image) {
58 |
59 | start := time.Now()
60 | for _, deployment := range deployments {
61 | if !strings.Contains(deployment.Namespace, cfg.NamespaceFilter) {
62 | continue
63 | }
64 |
65 | if !strings.Contains(deployment.ClusterName, cfg.ClusterFilter) {
66 | continue
67 | }
68 |
69 | imageFound := false
70 | for _, container := range deployment.Containers {
71 | if strings.Contains(container.Image.Name.FullName, cfg.ImageNameFilter) {
72 | imageFound = true
73 | continue
74 | }
75 | }
76 |
77 | if !imageFound {
78 | continue
79 | }
80 |
81 | filteredDeployments = append(filteredDeployments, deployment)
82 | }
83 |
84 | stats.DeploymentFilterDuration = time.Now().Sub(start)
85 | stats.FilteredDeploymentExportCount = len(filteredDeployments)
86 | start = time.Now()
87 |
88 | for _, image := range images {
89 | if strings.Contains(image.Name.FullName, cfg.ImageNameFilter) {
90 | filteredImages = append(filteredImages, image)
91 | }
92 |
93 | }
94 | stats.ImageFilterDuration = time.Now().Sub(start)
95 | stats.FilteredImageExportCount = len(filteredImages)
96 | return
97 | }
98 |
99 | var queryMap = map[string]string{}
100 |
101 | func BuildServerQuery(cfg config.ConfigType) string {
102 | var buffer bytes.Buffer
103 |
104 | for k, v := range cfg.QueryStrings() {
105 | if strings.TrimPrefix(v, "r/") != "" {
106 | buffer.WriteString(fmt.Sprintf("%s:%s", k, v))
107 | buffer.WriteString("+")
108 | }
109 | }
110 |
111 | ret := buffer.String()
112 |
113 | if len(ret) > 0 {
114 | os.Stderr.WriteString(fmt.Sprintf("Server query: %s\n", ret[:len(ret)-1]))
115 | return ret[:len(ret)-1]
116 | }
117 | return ""
118 | }
119 |
--------------------------------------------------------------------------------
/acs-export-example/pkg/table/table.go:
--------------------------------------------------------------------------------
1 | package table
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/charmbracelet/lipgloss"
8 | "github.com/charmbracelet/lipgloss/table"
9 | "github.com/pkg/errors"
10 | "golang.org/x/term"
11 |
12 | storage "github.com/stackrox/rox/generated/storage"
13 | )
14 |
15 | func RenderTable(deployments []*storage.Deployment, images []*storage.Image) error {
16 | imageMap := map[string]*storage.Image{}
17 |
18 | for _, image := range images {
19 | imageMap[image.Name.FullName] = image
20 | }
21 |
22 | width, _, err := term.GetSize(0)
23 | if err != nil {
24 | panic(errors.Wrap(err, "could not get terminal size"))
25 | }
26 |
27 | t := table.New().
28 | Border(lipgloss.NormalBorder()).
29 | BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("#84A59D"))).
30 | Width(width).
31 | StyleFunc(func(row, col int) lipgloss.Style {
32 | switch {
33 | case row == 0:
34 | return lipgloss.NewStyle().Bold(true)
35 | case row%2 == 0:
36 | return lipgloss.NewStyle().Foreground(lipgloss.Color("#EA9285"))
37 | default:
38 | return lipgloss.NewStyle().Foreground(lipgloss.Color("#F5CAC3"))
39 | }
40 | }).
41 | Headers("CVE", "CVSS", "Cluster", "Namespace", "Image", "Component", "Fixable")
42 |
43 | for _, d := range deployments {
44 | for _, container := range d.Containers {
45 | imageName := container.Image.Name.FullName
46 |
47 | if strings.Contains(imageName, "openshift-release-dev") {
48 | continue
49 | }
50 |
51 | image, found := imageMap[imageName]
52 | if !found || image.Scan == nil {
53 | continue
54 | }
55 |
56 | if len(imageName) > 60 {
57 | imageName = imageName[:57] + "..."
58 | }
59 |
60 | for _, component := range image.Scan.Components {
61 | for _, vuln := range component.Vulns {
62 | fixable := ""
63 | if vuln.GetFixedBy() != "" {
64 | fixable = "fixable"
65 | }
66 |
67 | t.Row(vuln.Cve, fmt.Sprint(vuln.Cvss), d.ClusterName, d.Namespace, imageName, component.Name, fixable)
68 | }
69 | }
70 | }
71 | }
72 |
73 | fmt.Println(t)
74 | return nil
75 | }
76 |
--------------------------------------------------------------------------------
/acs-export-example/readme.md:
--------------------------------------------------------------------------------
1 | # ACS/StackRox Export CLI
2 |
3 | 
4 |
5 | A CLI that generates a CVE report based on the ACS export APIs.
6 |
7 | ```
8 | $ ./acs-export-example -h
9 | CLI to browse data pulled from ACS (Advanced Cluster Security) (i.e. StackRox).
10 |
11 | Usage:
12 | acs-export-example [flags]
13 |
14 | Flags:
15 | -c, --cluster string Cluster client-side filter.
16 | -t, --filter-type string Where to do the param-based filtering. Available options: [client, server] (default "client")
17 | -f, --fixable string Filter on whether a cve is fixable. Available options: [true, false, ""].
18 | -h, --help help for acs-export-example
19 | -i, --image string Image name client-side filter.
20 | -n, --namespace string Namespace client-side filter.
21 | -o, --output string Output format. Available options: [table, csv] (default "table")
22 | -q, --query string Pass a query string to the server. Incompatible with --filter-type=server
23 | -s, --stats Print stats about the export
24 | -v, --vuln string Vulnerability client-side filter.
25 | ```
26 |
27 | ## Setup
28 |
29 | Currently the only way to configure the Central endpoint is to set these two environment variables:
30 |
31 | export ROX_ENDPOINT=https://central.stackrox.com
32 | export ROX_API_TOKEN=eyJh... # base64-encoded JWT
33 |
34 | ## Output Formats
35 |
36 | Print a table to the console with all reported vulnerabilities:
37 |
38 | $ ./acs-export-example
39 |
40 | Output in CSV format instead:
41 |
42 | $ ./acs-export-example -o csv
43 |
44 | ## Filters
45 |
46 | Filter by cluster:
47 |
48 | $ ./acs-export-example -c acs-stage-cluster
49 |
50 | Filter by cluster and namespace:
51 |
52 | $ ./acs-export-example -c acs-stage-cluster -n stackrox
53 |
54 | Filter by CVE/vulnerability name:
55 |
56 | $ ./acs-export-example -v CVE-2021-0000
57 |
58 | Filter by image name:
59 |
60 | $ ./acs-export-example -i quay.io/kylape/my-image-repo
61 |
62 | Filter on whether a vulnerability is considered fixable or not:
63 |
64 | $ ./acs-export-example -f true # Only output fixable vulns
65 |
66 | The above filters are performed on the client side by default.
67 | Use the `--filter-type=server` option to instead build a query string to have the filters executed on the server:
68 |
69 | $ ./acs-export-example -i quay.io/kylape/my-image-repo -t server
70 |
71 | If you'd rather build the query string for the server yourself:
72 |
73 | $ ./acs-export-example -q "CLUSTER:acs-stage-cluster+NAMESPACE:stackrox+CVE:r/CVE-2021-0000"
74 |
75 | ## Stats
76 |
77 | The `--stats` option prints various timings and counts that may be interesting to use for performance analysis:
78 |
79 | ```
80 | $ ./acs-export-example -o csv -s > export.csv
81 | Fetching deployments
82 | Fetching images
83 | Durations:
84 | Connect: 295.686µs
85 | Deployment Export: 611.136684ms
86 | Image Export: 4.048604959s
87 | Deployment Filtering: 47.291µs
88 | Image Filtering: 2.547318ms
89 |
90 | Counts:
91 | Deployments: 444
92 | Images: 375
93 | Filtered Deployments: 444
94 | Filtered Images: 353
95 | ```
96 |
97 | ## Building
98 |
99 | ```
100 | go build
101 | ```
102 |
--------------------------------------------------------------------------------
/api-examples/README.md:
--------------------------------------------------------------------------------
1 | # ACS API Examples
2 |
3 | ### Examples of API usage to perform configuration and reporting tasks with Red Hat Advanced Cluster Security
4 |
5 | These examples use an ACS API Token [that you can issue from the ACS Central Integrations page](https://docs.openshift.com/acs/3.71/cli/getting-started-cli.html#cli-authentication_cli-getting-started)
6 |
7 | ---
8 |
9 | The examples assume two environment variables:
10 | CENTRAL is the exposed hostname or IP address of the ACS Central pod's route or loadbalancer
11 | ROX_API_TOKEN is the full text of a token created in the Central UI's Integrations page
12 |
13 | API calls to ACS' RESTful API endpoints require the API token in the Authorization: Bearer header. The RESTful API documentation is available in the Central UI.
14 |
15 | ```
16 | export CENTRAL=central-stackrox.apps.example.com
17 | export ROX_API_TOKEN=eyJhbGciOiJSUzI1NiIsIm...HYkJj2uWo
18 | ```
19 |
20 | ---
21 |
22 | Absurdly simple example:
23 | ```
24 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" https://$CENTRAL:443/v1/ping
25 | ```
26 |
--------------------------------------------------------------------------------
/api-examples/authprovider-minrole.md:
--------------------------------------------------------------------------------
1 | This is a two-stage process to add the auth provider and the minimum role with the API.
2 |
3 | this is some shell script shorthand:
4 | ```bash
5 | OPENSHIFT_AUTH='{"id":"","name":"OpenShift","type":"openshift","config":{},"uiEndpoint":"'"${CENTRAL}"'","enabled":true}'
6 | CURLEXEC=$( curl -s -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X POST "https://${CENTRAL}/v1/authProviders" -d "$OPENSHIFT_AUTH" )
7 | ```
8 |
9 | CENTRAL is the route hostname for your Central app
10 | and then the min access role:
11 | ```bash
12 | # add minimum access role
13 | MIN_ROLE='{"previous_groups":[],"required_groups":[{"props":{"authProviderId":"'"${AUTH_ID}"'"},"roleName":"Analyst"}]}'
14 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X POST "https://${CENTRAL}/v1/groupsbatch" -d "$MIN_ROLE"
15 | ```
16 |
17 | here's a naive but complete script:
18 | ```bash
19 | CENTRAL=central.example.com
20 | CENTRAL_PASS="AdminPassForCentral"
21 |
22 | # get an API token; not needed if already available
23 | POLICY_JSON='{ "name": "mytoken", "role":"Admin"}'
24 | APIURL="https://$CENTRAL/v1/apitokens/generate"
25 | ROX_API_TOKEN=$(curl -s -k -u admin:$CENTRAL_PASS -H 'Content-Type: application/json' -X POST -d "$POLICY_JSON" "$APIURL" | jq -r '.token')
26 |
27 | # create the openshift auth SSO
28 | OPENSHIFT_AUTH='{"id":"","name":"OpenShift","type":"openshift","config":{},"uiEndpoint":"'"${CENTRAL}"'","enabled":true}'
29 | CURLEXEC=$( curl -s -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X POST "https://${CENTRAL}/v1/authProviders" -d "$OPENSHIFT_AUTH" )
30 |
31 | echo $CURLEXEC
32 |
33 | AUTH_ID=echo $CURLEXEC | jq -r '.id'
34 |
35 | echo "Created integration with ID $AUTH_ID"
36 | echo
37 |
38 | # add minimum access role
39 | MIN_ROLE='{"previous_groups":[],"required_groups":[{"props":{"authProviderId":"'"${AUTH_ID}"'"},"roleName":"Analyst"}]}'
40 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X POST "https://${CENTRAL}/v1/groupsbatch" -d "$MIN_ROLE"
41 | echo
42 | ```
43 |
44 |
--------------------------------------------------------------------------------
/api-examples/delete_group.md:
--------------------------------------------------------------------------------
1 | ```bash
2 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X DELETE "https://ce$CENTRAL/v1/groups?authProviderId=blah&key=groups&value=blah&id=io.stackrox.authz.group.d753bd68-6769-4858-8d34-d996461812dc"
3 | ```
4 |
--------------------------------------------------------------------------------
/api-examples/groupsbatch_newgroups.md:
--------------------------------------------------------------------------------
1 | We can do a batch update to add groups in the following manner:
2 |
3 |
4 | As always, we export the Central address and your API token:
5 | ```
6 | export CENTRAL=YOUR_CENTRAL_ADDRESS
7 | ```
8 | ```
9 | export ROX_API_TOKEN=eyJhb....BlAh
10 | ```
11 | Retrive your AuthProviderID:
12 | ```
13 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" https://$CENTRAL/v1/authProviders
14 | ```
15 | ```
16 | export AUTH_ID=Id_from_previous_curl
17 | ```
18 |
19 |
20 | Utilizing your AuthProvider ID, you can define utilize the "value" field to map your groups to the needed roles.
21 | ```bash
22 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X POST "https://$CENTRAL/v1/groupsbatch" -d '{ "requiredGroups": [{"props":{"id":"","authProviderId":"$AUTH_ID","key":"groups","value":"LDAP_Analyst_Group"},"roleName":"Analyst"},{"props":{"id":"","authProviderId":"$AUTH_ID","key":"groups","value":"LDAP_Analyst_Group_2"},"roleName":"Analyst"}]}'
23 | ```
24 |
--------------------------------------------------------------------------------
/api-examples/groupservice_creategroup.md:
--------------------------------------------------------------------------------
1 | Creating a single group can be achieved by providing a key, value pair and mapping it to a role.
2 |
3 | ```json
4 | {
5 | "props": {
6 | "id": "string",
7 | "authProviderId": "string",
8 | "key": "string",
9 | "value": "string"
10 | },
11 | "roleName": "string"
12 | }
13 | ```
14 |
15 | ```bash
16 | curl -k -H "Authorization: Bearer ${ROX_API_TOKEN}" --header "Content-Type: application/json" -X POST "https://$CENTRAL/v1/groups" -d '{"props":{"id":"","authProviderId":"38c7afcd-d943-4163-bdb0-7787f9cdb3a4","key":"groups","value":"LDAP_Analyst_Group"},"roleName":"Analyst"}'
17 | ```
18 |
19 |
--------------------------------------------------------------------------------
/api-examples/simple-alerts.md:
--------------------------------------------------------------------------------
1 | #Simple examples of ACS "alert" objects, the structure behind Violations in the UI
2 |
3 | Simple curl examples
4 |
5 | These examples all use environment variables for the Hostname of ACS Central (Control Plane) and for the contents of a StackRox API token that you can create from the UI under Platform Integration -> Integrations.
6 |
7 |
8 | Super simple alert retrieval:
9 | ```bash
10 | curl -k -H "Authorization: Bearer ${TOKEN}" https://$CENTRAL/v1/alerts | jq -r '.'
11 | ```
12 |
13 | Using a search query for alerts:
14 | ```bash
15 | curl -k -H "Authorization: Bearer ${TOKEN}" https://$CENTRAL/v1/alerts?query="Namespace:test" | jq -r '.'
16 | ```
17 |
18 | Combination search query:
19 | ```bash
20 | curl -k -H "Authorization: Bearer ${TOKEN}" https://$CENTRAL/v1/alerts?query="Cluster:kube+Namespace:stackrox,kube-system" | jq -r '.'
21 | ```
22 |
23 | Combination search query with URL-safe encoding:
24 | ```bash
25 | curl -k -H "Authorization: Bearer ${TOKEN}" https://$CENTRAL/v1/alerts?query=Severity%3AHIGH_SEVERITY%2BNamespace%3Apayments | jq -r '.'
26 | ```
27 |
28 | Search filter for time range:
29 | ```bash
30 | curl -k -H "Authorization: Bearer ${TOKEN}" https://$CENTRAL/v1/alerts?query==Violation%20Time%3A%3E1d | jq -r '.'
31 | ```
32 |
--------------------------------------------------------------------------------
/backups/api-key-secret.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: rox-api-token
5 | stringData:
6 | token: ### insert api token generated by stackrox
7 |
--------------------------------------------------------------------------------
/backups/cron-backup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1
2 | kind: CronJob
3 | metadata:
4 | name: backup-cron
5 | namespace: stackrox
6 | spec:
7 | concurrencyPolicy: Allow
8 | failedJobsHistoryLimit: 1
9 | jobTemplate:
10 | metadata:
11 | creationTimestamp: null
12 | spec:
13 | template:
14 | metadata:
15 | creationTimestamp: null
16 | spec:
17 | containers:
18 | - args:
19 | - --output
20 | - /mnt
21 | - -e
22 | - ###insert end point here or be professional and use a variable
23 | - --insecure-skip-tls-verify
24 | command:
25 | - roxctl
26 | - central
27 | - backup
28 | env: ###either retreieve the rox pass or create a token and store it in a secret the set the env, don't use passwords in Git!
29 | - name: ROX_API_TOKEN
30 | valueFrom:
31 | secretKeyRef:
32 | key: token
33 | name: rox-api-token
34 | image: registry.redhat.io/advanced-cluster-security/rhacs-roxctl-rhel8:3.71.2
35 | imagePullPolicy: IfNotPresent
36 | name: backup-cron
37 | resources: {}
38 | terminationMessagePath: /dev/termination-log
39 | terminationMessagePolicy: File
40 | volumeMounts:
41 | - mountPath: /mnt
42 | name: stackrox-backups-uat
43 | dnsPolicy: ClusterFirst
44 | restartPolicy: OnFailure
45 | schedulerName: default-scheduler
46 | securityContext: {}
47 | terminationGracePeriodSeconds: 30
48 | volumes:
49 | - name: stackrox-backups-uat
50 | persistentVolumeClaim:
51 | claimName: stackrox-backups-uat
52 | schedule: 05 1 * * *
53 | successfulJobsHistoryLimit: 3
54 | suspend: false
55 |
--------------------------------------------------------------------------------
/backups/cron-clean-backup.yaml:
--------------------------------------------------------------------------------
1 | kind: CronJob
2 | apiVersion: batch/v1
3 | metadata:
4 | name: clean-backup-cron
5 | namespace: stackrox
6 | spec:
7 | schedule: 10 1 * * *
8 | concurrencyPolicy: Allow
9 | suspend: false
10 | jobTemplate:
11 | metadata:
12 | creationTimestamp: null
13 | spec:
14 | template:
15 | metadata:
16 | creationTimestamp: null
17 | spec:
18 | volumes:
19 | - name: stackrox-backups-uat
20 | persistentVolumeClaim:
21 | claimName: stackrox-backups-uat
22 | containers:
23 | - name: clean-backup-cron
24 | image: registry.access.redhat.com/ubi8/ubi
25 | args:
26 | - /bin/sh
27 | - '-c'
28 | - 'find /mnt* -mtime +30 -exec rm {} \;'
29 | resources: {}
30 | volumeMounts:
31 | - name: stackrox-backups-uat
32 | mountPath: /mnt
33 | terminationMessagePath: /dev/termination-log
34 | terminationMessagePolicy: File
35 | imagePullPolicy: IfNotPresent
36 | restartPolicy: OnFailure
37 | terminationGracePeriodSeconds: 30
38 | dnsPolicy: ClusterFirst
39 | securityContext: {}
40 | schedulerName: default-scheduler
41 | successfulJobsHistoryLimit: 3
42 | failedJobsHistoryLimit: 1
43 | status: {}
44 |
45 |
--------------------------------------------------------------------------------
/backups/readme.md:
--------------------------------------------------------------------------------
1 | This is a simple example of running ACS/Stackrox backups in a container and storing them on a persistent volume.
2 |
3 | api-key-secret.yaml creates a secret from a generated rox api token
4 | - you must fill the token value in with a stackrox api token. You can see how to do that [here](https://access.redhat.com/documentation/en-us/red_hat_advanced_cluster_security_for_kubernetes/3.71/html-single/roxctl_cli/index#cli-authentication_cli-getting-started)
5 |
6 | cron-backups.yaml creates a container from the roxctl image and runs a backup storing it in a PVC mounted on /mnt
7 | - You can utilize ROX_CENTRAL_ADDRESS as an env variable as well
8 | - The above env variables were not used in this case with hopes of showing simple examples that could be built upon.
9 |
10 | retreive-backups-pod.yaml creates a simple container that mounts a PVC where you could retrieve a backup, if needed. (obviously you need to mount the correct PVC)
11 |
12 | There are many ways to achieve the backup task. This was done for an environment where access was limited and the ACS team only had access to persistent storage via the cluster.
13 |
--------------------------------------------------------------------------------
/backups/retrieve-backups-pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: retrieve-backups
5 | namespace: stackrox
6 | spec:
7 | containers:
8 | - name: retrieve-backups
9 | image: 'registry.access.redhat.com/ubi8/ubi'
10 | volumeMounts:
11 | - mountPath: /mnt
12 | name: stackrox-backups-uat
13 | command: [ "/bin/bash", "-c", "--" ]
14 | args: [ "while true; do sleep 30; done;" ]
15 | volumes:
16 | - name: stackrox-backups-uat
17 | persistentVolumeClaim:
18 | claimName: stackrox-backups-uat
19 |
--------------------------------------------------------------------------------
/ci/Azure DevOps/Pipelines/README.md:
--------------------------------------------------------------------------------
1 | # Azure DevOps Pipeline Sample
2 |
3 | This sample is a fragment of an azure-pipelines.yml file that downloads `roxctl` and uses it to scan an image, check it against configured system policies, and generate a CSV with all packages & vulnerabilities broken down by the layer in which they were introduced. It saves all this output as artifacts of the build.
4 |
5 | In order to use this sample, you should set two variables in your Azure DevOps project:
6 |
7 | * roxcentralendpoint -- this is the exposed address & port for your StackRox Central deployment in the form `stackrox.contoso.com:443`.
8 | * roxapitoken -- this is an API token with at least CI privileges.
9 |
10 | Change `vulnerables/cve-2017-7494` to match the image you want to scan as part of the build.
11 |
12 | OWNER: neilcar
13 |
14 | LATEST TESTED: 3.0.53.0
15 |
--------------------------------------------------------------------------------
/ci/Azure DevOps/Pipelines/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - master
3 |
4 | resources:
5 | - repo: self
6 |
7 | stages:
8 | - stage: Scan
9 | jobs:
10 | - job: Scan
11 | displayName: Scan with StackRox
12 | pool:
13 | vmImage: 'ubuntu-latest'
14 | steps:
15 | - script: |
16 | mkdir $(System.DefaultWorkingDirectory)/artifacts
17 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl
18 | chmod +x ./roxctl
19 | ./roxctl image scan -e $ROX_CENTRAL_ENDPOINT --image vulnerables/cve-2017-7494 --format csv > $(System.DefaultWorkingDirectory)/artifacts/image_scan.csv
20 | ./roxctl image check -e $ROX_CENTRAL_ENDPOINT --image vulnerables/cve-2017-7494 > $(System.DefaultWorkingDirectory)/artifacts/image_check.txt
21 | displayName: 'StackRox image scan'
22 | env:
23 | ROX_API_TOKEN: $(roxapitoken)
24 | ROX_CENTRAL_ENDPOINT: '$(roxcentralendpoint)'
25 | - task: PublishPipelineArtifact@1
26 | displayName: 'Publish Pipeline Artifact'
27 | inputs:
28 | targetPath: '$(System.DefaultWorkingDirectory)/artifacts'
29 | artifact: 'StackRox Output'
30 | condition: succeededOrFailed()
31 |
--------------------------------------------------------------------------------
/ci/CircleCI/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # StackRox inline orb sample
2 | # author neil@stackrox.com
3 |
4 | version: 2.1
5 | orbs:
6 | rox-orb:
7 | jobs:
8 | rox-deployment-check:
9 | machine: true
10 | parameters:
11 | rox_api_token:
12 | description: API key with CI permissions
13 | type: string
14 | rox_central_endpoint:
15 | description: URL of Central (central.contoso.com:443 for example)
16 | type: string
17 | rox_deployment:
18 | description: Path/name of yaml to check
19 | type: string
20 | steps:
21 | - checkout
22 | - rox-roxctl-install:
23 | rox_api_token: <>
24 | rox_central_endpoint: <>
25 | - run: >-
26 | ./roxctl deployment check -e <> --file <>
27 | rox-image-scan:
28 | machine: true
29 | parameters:
30 | rox_api_token:
31 | description: API key with CI permissions
32 | type: string
33 | rox_central_endpoint:
34 | description: URL of Central (central.contoso.com:443 for example)
35 | type: string
36 | rox_image:
37 | description: Name of image to scan (neilcar/testimage:5 or registry.contoso.com/db_broker:latest for example)
38 | type: string
39 | output_format:
40 | description: Format of image scan output (table | csv | json) (default "json")
41 | type: string
42 | default: "json"
43 | steps:
44 | - rox-roxctl-install:
45 | rox_api_token: <>
46 | rox_central_endpoint: <>
47 | - run: >-
48 | ./roxctl image scan -e <> --image <> --output <>
49 | rox-image-check:
50 | machine: true
51 | parameters:
52 | rox_api_token:
53 | description: API key with CI permissions
54 | type: string
55 | rox_central_endpoint:
56 | description: URL of Central (central.contoso.com:443 for example)
57 | type: string
58 | rox_image:
59 | description: Name of image to check (neilcar/testimage:5 or registry.contoso.com/db_broker:latest for example)
60 | type: string
61 | output_format:
62 | description: Format of image scan output (table | csv | json | junit) (default "table")
63 | type: string
64 | default: "table"
65 | steps:
66 | - rox-roxctl-install:
67 | rox_api_token: <>
68 | rox_central_endpoint: <>
69 | - run: >-
70 | ./roxctl image check -e <> --image <> --output <>
71 | commands:
72 | rox-roxctl-install:
73 | parameters:
74 | rox_api_token:
75 | description: API key with CI permissions
76 | type: string
77 | rox_central_endpoint:
78 | description: URL of Central (central.contoso.com:443 for example)
79 | type: string
80 | steps:
81 | - run: >-
82 | curl -k -L -H "Authorization: Bearer <>" https://<>/api/cli/download/roxctl-linux --output ./roxctl
83 | - run: chmod +x ./roxctl
84 |
85 | workflows:
86 | scanimage:
87 | when: always
88 | jobs:
89 | - rox-orb/rox-image-scan:
90 | context: rox
91 | name: scan an image
92 | rox_central_endpoint: $ROX_CENTRAL_ENDPOINT
93 | rox_api_token: $ROX_API_TOKEN
94 | rox_image: neilcar/jenkins-demo:latest
95 | - rox-orb/rox-image-check:
96 | context: rox
97 | name: check an image against build-time policies
98 | rox_central_endpoint: $ROX_CENTRAL_ENDPOINT
99 | rox_api_token: $ROX_API_TOKEN
100 | rox_image: neilcar/jenkins-demo:latest
101 | - rox-orb/rox-deployment-check:
102 | context: rox
103 | name: Check deployment
104 | rox_central_endpoint: $ROX_CENTRAL_ENDPOINT
105 | rox_api_token: $ROX_API_TOKEN
106 | rox_deployment: deploy.yml
107 |
108 |
--------------------------------------------------------------------------------
/ci/CircleCI/README.md:
--------------------------------------------------------------------------------
1 | # CircleCI Orb Sample
2 |
3 |
4 | This sample uses an inline orb that exposes three jobs
5 |
6 | ```
7 | rox-image-check:
8 | description: does a `roxctl image check`
9 | parameters:
10 | rox_api_token:
11 | description: API key with CI permissions
12 | type: string
13 | rox_central_endpoint:
14 | description: URL of Central (central.contoso.com:443 for example)
15 | type: string
16 | rox_image:
17 | description: Name of image to check (neilcar/testimage:5 or registry.contoso.com/db_broker:latest for example)
18 | type: string
19 | output_format:
20 | description: Format of image scan output (table | csv | json | junit) (default "table")
21 | type: string
22 | ```
23 | ```
24 | job: rox-image-scan
25 | description: does a `roxctl image scan`
26 | parameters:
27 | rox_api_token:
28 | description: API key with CI permissions
29 | type: string
30 | rox_central_endpoint:
31 | description: URL of Central (central.contoso.com:443 for example)
32 | type: string
33 | rox_deployment:
34 | description: Path/name of yaml to check
35 | type: string
36 | output_format:
37 | description: Format of image scan output (table | csv | json) (default "json")
38 | type: string
39 | ```
40 | ```
41 | job: rox-deployment-check
42 | description: does a `roxctl deployment check`
43 | parameters:
44 | rox_api_token:
45 | description: API key with CI permissions
46 | type: string
47 | rox_central_endpoint:
48 | description: URL of Central (central.contoso.com:443 for example)
49 | type: string
50 | rox_deployment:
51 | description: Path/name of yaml to check
52 | type: string
53 | ```
54 |
55 | OWNER: neilcar
56 |
57 | LATEST TESTED: 3.68.1
58 |
--------------------------------------------------------------------------------
/ci/CircleCI/deploy.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: nginx
5 | labels:
6 | app: nginx
7 | spec:
8 | containers:
9 | - name: nginx
10 | image: nginx
11 | ports:
12 | - containerPort: 80
13 | securityContext:
14 | privileged: true
15 |
--------------------------------------------------------------------------------
/ci/GitHub/kube-linter/.github/actions/kube-lint/action.yml:
--------------------------------------------------------------------------------
1 | name: 'kube-linter'
2 | description: 'Scan directory with kube-linter'
3 | inputs:
4 | directory:
5 | description: 'Directory to scan '
6 | required: true
7 | config:
8 | description: 'Path to config file'
9 | required: false
10 | outputs:
11 | lint-txt:
12 | description: 'Output from linting'
13 | value: ${{ steps.lint.outputs.lint-txt }}
14 | runs:
15 | using: "composite"
16 | steps:
17 | - name: Download latest kube-linter
18 | run: |
19 | LOCATION=$(curl -s https://api.github.com/repos/stackrox/kube-linter/releases/latest \
20 | | grep "tag_name" \
21 | | awk '{print "https://github.com/stackrox/kube-linter/releases/download/" substr($2, 2, length($2)-3) "/kube-linter-linux.tar.gz"}')
22 | curl -s -L -o kube-linter-linux.tar.gz $LOCATION
23 | tar -xf kube-linter-linux.tar.gz -C "${GITHUB_WORKSPACE}/"
24 | shell: bash
25 | - id: lint
26 | run: |
27 | cd "${GITHUB_WORKSPACE}"
28 | if [ -z ${{ inputs.config }} ]; then
29 | export CONFIG=""
30 | else
31 | export CONFIG="--config ${{ inputs.config }}"
32 | fi
33 | ./kube-linter $CONFIG lint ${{ inputs.directory }}
34 | shell: bash
35 |
36 |
--------------------------------------------------------------------------------
/ci/GitHub/kube-linter/.github/workflows/kube-linter.yml:
--------------------------------------------------------------------------------
1 | name: Check Kubernetes YAMLs
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | scan:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 | - name: Scan repo
15 | id: kube-lint-repo
16 | uses: ./.github/actions/kube-lint
17 | with:
18 | directory: yamls
19 | config: .kube-linter/config.yaml
20 |
21 |
--------------------------------------------------------------------------------
/ci/GitHub/kube-linter/.kube-linter/config.yaml:
--------------------------------------------------------------------------------
1 | # customChecks defines custom checks.
2 | customChecks:
3 | - name: "required-label-app"
4 | template: "required-label"
5 | params:
6 | key: "app"
7 | checks:
8 | # if doNotAutoAddDefaults is true, default checks are not automatically added.
9 | doNotAutoAddDefaults: false
10 | # addAllBuiltIn, if set, adds all built-in checks. This allows users to
11 | # explicitly opt-out of checks that are not relevant using Exclude.
12 | # Takes precedence over doNotAutoAddDefaults, if both are set.
13 | addAllBuiltIn: false
14 | # include explicitly adds checks, by name. You can reference any of the built-in checks.
15 | # Note that customChecks defined above are included automatically.
16 | include:
17 | - "required-label-owner"
18 | # exclude explicitly excludes checks, by name. exclude has the highest priority: if a check is
19 | # in exclude, then it is not considered, even if it is in include as well.
20 | exclude:
21 | - "privileged"
22 |
--------------------------------------------------------------------------------
/ci/GitHub/kube-linter/README.md:
--------------------------------------------------------------------------------
1 | # kube-lint GitHub action
2 |
3 | This is a GitHub action for scanning Kubernetes deployment files with [kube-linter](https://github.com/stackrox/kube-linter). This includes both the action itself (.github/actions/kubelint) and sample GitHub workflow (.github/workflows) and a test YAML.
4 |
5 | Quick deployment:
6 |
7 | 1. Create a new GitHub repo.
8 | 2. Push all files from this sample into the repo.
9 | 3. The `kube-linter.yml` workflow will run as an action every time there's a new push to this repo.
10 |
11 | More info on creating a repo with a GitHub action like this and using it broadly can be [found here](https://docs.github.com/en/free-pro-team@latest/actions/creating-actions/creating-a-composite-run-steps-action)
12 |
13 | The action takes two parameters.
14 |
15 | ```
16 | - name: Scan repo
17 | id: kube-lint-repo
18 | uses: ./.github/actions/kube-lint
19 | with:
20 | directory: yamls
21 | config: .kube-linter/config.yaml
22 | ```
23 |
24 | * `directory` is mandatory -- this is the directory of deployment files to scan.
25 | * `config` is optional -- this is the path to a [configuration file](https://github.com/stackrox/kube-linter/blob/main/config.yaml.example) if you wish to use a non-default configuration.
26 |
27 | LATEST TESTED VERSION: 0.1.1
28 |
--------------------------------------------------------------------------------
/ci/GitHub/kube-linter/yamls/deploy.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: nginx-deployment
5 | labels:
6 | app: nginx
7 | spec:
8 | replicas: 3
9 | selector:
10 | matchLabels:
11 | app: nginx
12 | template:
13 | metadata:
14 | labels:
15 | app: nginx
16 | spec:
17 | containers:
18 | - name: nginx
19 | image: nginx:1.14.2
20 | ports:
21 | - containerPort: 80
--------------------------------------------------------------------------------
/ci/GitHub/stackrox-action/.github/actions/stackrox-check/action.yml:
--------------------------------------------------------------------------------
1 | name: 'stackrox-scan'
2 | description: 'Scan image with StackRox'
3 | inputs:
4 | central-endpoint:
5 | description: 'Central endpoint in the format stackrox.contoso.com:443'
6 | required: true
7 | api-token:
8 | description: 'API token with CI permissions'
9 | required: true
10 | image:
11 | description: 'Full name of the image to scan -- gcr.io/stackrox/testimage:5.1'
12 | required: true
13 | runs:
14 | using: "composite"
15 | steps:
16 | - run: >
17 | curl -s -k -L -H "Authorization: Bearer ${{ inputs.api-token }}" https://${{ inputs.central-endpoint }}/api/cli/download/roxctl-linux --output ./roxctl
18 | shell: bash
19 | - run: chmod +x ./roxctl
20 | shell: bash
21 | - id: scan-check
22 | run: |
23 | ./roxctl image check --force -e ${{ inputs.central-endpoint }} --image ${{ inputs.image }}
24 | env:
25 | ROX_API_TOKEN: ${{ inputs.api-token }}
26 | shell: bash
27 |
--------------------------------------------------------------------------------
/ci/GitHub/stackrox-action/.github/actions/stackrox-scan/action.yml:
--------------------------------------------------------------------------------
1 | name: 'stackrox-scan'
2 | description: 'Scan image with StackRox'
3 | inputs:
4 | central-endpoint:
5 | description: 'Central endpoint in the format stackrox.contoso.com:443'
6 | required: true
7 | api-token:
8 | description: 'API token with CI permissions'
9 | required: true
10 | image:
11 | description: 'Full name of the image to scan -- gcr.io/stackrox/testimage:5.1'
12 | required: true
13 | format:
14 | description: 'Format of output. Valid values are json, csv, and pretty'
15 | required: 'false'
16 | default: 'pretty'
17 | runs:
18 | using: "composite"
19 | steps:
20 | - run: >
21 | curl -s -k -L -H "Authorization: Bearer ${{ inputs.api-token }}" https://${{ inputs.central-endpoint }}/api/cli/download/roxctl-linux --output ./roxctl
22 | shell: bash
23 | - run: chmod +x ./roxctl
24 | shell: bash
25 | - id: scan-info
26 | run: |
27 | ./roxctl image scan -e ${{ inputs.central-endpoint }} --image ${{ inputs.image }} --format ${{ inputs.format }}
28 | env:
29 | ROX_API_TOKEN: ${{ inputs.api-token }}
30 | shell: bash
31 |
--------------------------------------------------------------------------------
/ci/GitHub/stackrox-action/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | on: [push]
2 |
3 | jobs:
4 | scan:
5 | runs-on: ubuntu-latest
6 | name: Scan image
7 | steps:
8 | - uses: actions/checkout@v2
9 | - id: scan
10 | uses: ./.github/actions/stackrox-scan
11 | with:
12 | image: 'vulnerables/cve-2017-7494'
13 | central-endpoint: ${{ secrets.ROX_CENTRAL_ENDPOINT }}
14 | api-token: ${{ secrets.ROX_API_TOKEN }}
15 | - id: check
16 | uses: ./.github/actions/stackrox-check
17 | with:
18 | image: 'vulnerables/cve-2017-7494'
19 | central-endpoint: ${{ secrets.ROX_CENTRAL_ENDPOINT }}
20 | api-token: ${{ secrets.ROX_API_TOKEN }}
21 |
--------------------------------------------------------------------------------
/ci/GitHub/stackrox-action/README.md:
--------------------------------------------------------------------------------
1 | # StackRox GitHub actions
2 |
3 | This is a GitHub action for scanning Docker images and checking them against policies. This sample includes both the actions themselves (.github/actions) and a sample workflow (.github/workflows)
4 |
5 | Quick deployment:
6 |
7 | 1. Create a new GitHub repo.
8 | 2. Push all files from this sample into the repo.
9 | 3. The `main.yml` workflow will run as an action every time there's a new push to this repo.
10 |
11 | More info on creating a repo with a GitHub action like this and using it broadly can be [found here](https://docs.github.com/en/free-pro-team@latest/actions/creating-actions/creating-a-composite-run-steps-action)
12 |
13 | There are two actions in this sample -- `stackrox-scan` and `stackrox-check`.
14 |
15 | `stackrox-scan` returns the JSON with the full analysis of the image composition including components & vulnerabilities. This is useful for getting everything StackRox knows about the image.
16 |
17 | `stackrox-check` tests the image against configured policies. If any violated policies are enforced, this will pass a non-zero return code back, causing the build to fail.
18 |
19 | Both actions take the same parameters:
20 |
21 | ```
22 | - id: check
23 | uses: ./.github/actions/stackrox-check
24 | with:
25 | image: 'vulnerables/cve-2017-7494'
26 | central-endpoint: ${{ secrets.ROX_CENTRAL_ENDPOINT }}
27 | api-token: ${{ secrets.ROX_API_TOKEN }}
28 | ```
29 |
30 | All parameters are mandatory. You should store the API token and the endpoint for Central (in the format `stackrox.contoso.com:443`) in [GitHub encrypted secrets](https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets).
31 |
32 | * `image` is the image to be scanned -- `vulnerables/cve-2017-7494` for example.
33 | * `central-endpoint` is the location of the StackRox Central deployment.
34 | * `api-token` is the StackRox API token to be used. This token must have at least CI privileges.
35 |
36 | LATEST TESTED VERSION: 3.0.53.0
37 |
--------------------------------------------------------------------------------
/ci/GitLab/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | scan:
2 | stage: test
3 | script:
4 | - "curl -k -L -H \"Authorization: Bearer $ROX_API_TOKEN\" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl "
5 | - chmod a+x ./roxctl
6 | - ./roxctl image scan -e $ROX_CENTRAL_ENDPOINT --force --image my.registry/repo/image:latest
7 | - ./roxctl image check -e $ROX_CENTRAL_ENDPOINT --image my.registry/repo/image:latest
8 |
--------------------------------------------------------------------------------
/ci/GitLab/README.md:
--------------------------------------------------------------------------------
1 | # GitLab Sample
2 |
3 |
4 | This sample is a fragment of a .gitlab-ci.yml file that downloads `roxctl` and uses it to scan an image & check it against configured system policies.
5 |
6 | In order to use this sample, you should set two environment variables in your GitLab project:
7 |
8 | * ROX_CENTRAL_ENDPOINT -- this is the exposed address & port for your StackRox Central deployment in the form `stackrox.contoso.com:443`.
9 | * ROX_API_TOKEN -- this is an API token with at least CI privileges.
10 |
11 | Change `my.registry/repo/image:latest` to match the image you want to scan as part of the build.
12 |
13 | OWNER: neilcar
14 |
15 | LATEST TESTED: 3.0.51.0
--------------------------------------------------------------------------------
/ci/Tekton/README.md:
--------------------------------------------------------------------------------
1 | # Tekton / OpenShift Pipelines Sample
2 |
3 | ## Overview
4 |
5 | This sample includes ClusterTasks for:
6 |
7 | |ClusterTask|Description|
8 | |---|---|
9 | |`rox-image-scan`|Scan an image and return results formatted as json, csv, or human-readable|
10 | |`rox-image-check`|Check an image against build-time policies and return success/failure|
11 | |`rox-deployment-check`|Check a deployment yaml against deploy-time policies and return success/failure}|
12 |
13 | It also includes samples for creating secrets for the StackRox Central endpoint & API token as well as pipelines that utilize the image scanning & checking ClusterTasks.
14 |
15 | ## Installation & Testing
16 |
17 | Use `kubectl apply -f Tasks/` or `oc apply -f Tasks/` to create the ClusterTasks for use in the cluster.
18 |
19 | To use the samples, edit `rox-secrets.yml` to include the correct values, create a `pipeline-demo` namespace (or change the namespace in the deployment files in `Sample/`), and run `kubectl apply -f Sample/` / `oc apply -f Sample/`. To run the pipeline, trigger it from the Web UI or use `tkn pipeline start rox-pipeline -n pipeline-demo -p image=vulnerables/phpldapadmin-remote-dump` (passing in the image to be scanned in the `image` parameter).
--------------------------------------------------------------------------------
/ci/Tekton/Sample/rox-pipeline.yml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: Pipeline
3 | metadata:
4 | name: rox-pipeline
5 | namespace: pipeline-demo
6 | spec:
7 | description: Rox demo pipeline
8 | params:
9 | - name: image
10 | type: string
11 | description: Full name of image to scan (example -- gcr.io/rox/sample:5.0-rc1)
12 | tasks:
13 | - name: image-scan
14 | taskRef:
15 | name: rox-image-scan
16 | kind: ClusterTask
17 | params:
18 | - name: image
19 | value: $(params.image)
20 | - name: rox_api_token
21 | value: roxsecrets
22 | - name: rox_central_endpoint
23 | value: roxsecrets
24 | - name: output_format
25 | value: json
26 | - name: image-check
27 | taskRef:
28 | name: rox-image-check
29 | kind: ClusterTask
30 | params:
31 | - name: image
32 | value: $(params.image)
33 | - name: rox_api_token
34 | value: roxsecrets
35 | - name: rox_central_endpoint
36 | value: roxsecrets
37 |
--------------------------------------------------------------------------------
/ci/Tekton/Sample/rox-secrets.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | stringData:
3 | rox_central_endpoint: "{{ central_addr }}:{{ central_port }}"
4 | # The address:port tuple for StackRox Central (example - rox.stackrox.io:443)
5 | rox_api_token: "{{ rox_api_token }}"
6 | # StackRox API token with CI permissions
7 | # Refer to https://help.stackrox.com/docs/use-the-api/#generate-an-access-token
8 | kind: Secret
9 | metadata:
10 | name: roxsecrets
11 | namespace: pipeline-demo
12 | type: Opaque
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ci/Tekton/Tasks/rox-deployment-check-task.yml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: ClusterTask
3 | metadata:
4 | name: rox-deployment-check
5 | namespace: pipeline-demo
6 | spec:
7 | params:
8 | - name: rox_central_endpoint
9 | type: string
10 | description: Secret containing the address:port tuple for StackRox Central (example - rox.stackrox.io:443)
11 | - name: rox_api_token
12 | type: string
13 | description: Secret containing the StackRox API token with CI permissions
14 | - name: file
15 | type: string
16 | description: YAML file in the deployfiles workspace
17 | results:
18 | - name: check_output
19 | description: Output of `roxctl deployment check`
20 | workspaces:
21 | - name: deployfiles
22 | description: |
23 | The folder containing deployment files
24 | mountPath: /deployfile
25 | steps:
26 | - name: rox-deployment-check
27 | image: centos:8
28 | env:
29 | - name: ROX_API_TOKEN
30 | valueFrom:
31 | secretKeyRef:
32 | name: $(params.rox_api_token)
33 | key: rox_api_token
34 | - name: ROX_CENTRAL_ENDPOINT
35 | valueFrom:
36 | secretKeyRef:
37 | name: $(params.rox_central_endpoint)
38 | key: rox_central_endpoint
39 | script: |
40 | #!/usr/bin/env bash
41 | set +x
42 | cat /deployfile/deploy.yml
43 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl > /dev/null; echo "Getting roxctl"
44 | chmod +x ./roxctl > /dev/null
45 | ./roxctl deployment check --insecure-skip-tls-verify -e $ROX_CENTRAL_ENDPOINT -f /deployfile/$(params.file)
--------------------------------------------------------------------------------
/ci/Tekton/Tasks/rox-image-check-task.yml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: ClusterTask
3 | metadata:
4 | name: rox-image-check
5 | namespace: pipeline-demo
6 | spec:
7 | params:
8 | - name: rox_central_endpoint
9 | type: string
10 | description: Secret containing the address:port tuple for StackRox Central (example - rox.stackrox.io:443)
11 | - name: rox_api_token
12 | type: string
13 | description: Secret containing the StackRox API token with CI permissions
14 | - name: image
15 | type: string
16 | description: Full name of image to scan (example -- gcr.io/rox/sample:5.0-rc1)
17 | results:
18 | - name: check_output
19 | description: Output of `roxctl image check`
20 | steps:
21 | - name: rox-image-check
22 | image: centos:8
23 | env:
24 | - name: ROX_API_TOKEN
25 | valueFrom:
26 | secretKeyRef:
27 | name: $(params.rox_api_token)
28 | key: rox_api_token
29 | - name: ROX_CENTRAL_ENDPOINT
30 | valueFrom:
31 | secretKeyRef:
32 | name: $(params.rox_central_endpoint)
33 | key: rox_central_endpoint
34 | script: |
35 | #!/usr/bin/env bash
36 | set +x
37 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl > /dev/null; echo "Getting roxctl"
38 | chmod +x ./roxctl > /dev/null
39 | ./roxctl image check --insecure-skip-tls-verify -e $ROX_CENTRAL_ENDPOINT --image $(params.image)
--------------------------------------------------------------------------------
/ci/Tekton/Tasks/rox-image-scan-task.yml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: ClusterTask
3 | metadata:
4 | name: rox-image-scan
5 | namespace: pipeline-demo
6 | spec:
7 | params:
8 | - name: rox_central_endpoint
9 | type: string
10 | description: Secret containing the address:port tuple for StackRox Central (example - rox.stackrox.io:443)
11 | - name: rox_api_token
12 | type: string
13 | description: Secret containing the StackRox API token with CI permissions
14 | - name: image
15 | type: string
16 | description: Full name of image to scan (example -- gcr.io/rox/sample:5.0-rc1)
17 | - name: output_format
18 | type: string
19 | description: Output format (json | csv )
20 | default: json
21 | steps:
22 | - name: rox-image-scan
23 | image: centos:8
24 | env:
25 | - name: ROX_API_TOKEN
26 | valueFrom:
27 | secretKeyRef:
28 | name: $(params.rox_api_token)
29 | key: rox_api_token
30 | - name: ROX_CENTRAL_ENDPOINT
31 | valueFrom:
32 | secretKeyRef:
33 | name: $(params.rox_central_endpoint)
34 | key: rox_central_endpoint
35 | script: |
36 | #!/usr/bin/env bash
37 | set +x
38 | export NO_COLOR="True"
39 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl > /dev/null; echo "Getting roxctl"
40 | chmod +x ./roxctl > /dev/null
41 | ./roxctl image scan --insecure-skip-tls-verify -e $ROX_CENTRAL_ENDPOINT --image $(params.image) --output $(params.output_format)
42 |
--------------------------------------------------------------------------------
/ci/argo/README.md:
--------------------------------------------------------------------------------
1 | # Argo Workflow Example
2 |
3 | Provided is an Argo Workflow resource that will build, push, scan and check a container image.
4 | This workflow will also render a K8s deployment resource and check that against StackRox policies
5 |
6 | ### PreReqs:
7 | * Argo
8 | * K8s imagePullSecret named: `stackrox-io`
9 | * K8s secret: `rox-api` with the `data` key set to the StackRox API token
10 | * K8s secret: `regcred` with `config.json` container docker registry credentials (for pushing)
11 |
12 | ### Overrides:
13 | The workflow has the following values that can be overriden at submit time from the CLI:
14 | * `git-repo-path`: ex "https://github.com/logankimmel/hello-go.git"
15 | * `image-repo`: ex "docker.io/logankimmel/hello-go"
16 |
17 | ### Required Param:
18 | * `central`: Central hostname and port, ex: "central.rox.binbytes.io:443"
19 | * This must be declared on the command line:
20 | `argo submit argo.yml -n argo -v -p central="central.rox.binbytes.io:443"`
21 |
22 | LATEST TESTED: 3.0.50.0
--------------------------------------------------------------------------------
/ci/argo/argo.yml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: Workflow
3 | metadata:
4 | generateName: hello-go-
5 | labels:
6 | workflows.argoproj.io/archive-strategy: "false"
7 | spec:
8 | entrypoint: cicd
9 | arguments:
10 | parameters:
11 | - name: git-repo-path
12 | value: https://github.com/logankimmel/hello-go.git
13 | - name: image-repo
14 | value: logankimmel/hello-go
15 | - name: central
16 | value: "{{workflow.parameters.central}}"
17 | templates:
18 | - name: cicd
19 | steps:
20 | - - name: checkout
21 | template: checkout
22 | arguments:
23 | parameters:
24 | - name: git-repo-path
25 | value: "{{workflow.parameters.git-repo-path}}"
26 | - - name: build-push-docker
27 | template: build-push-docker
28 | arguments:
29 | artifacts:
30 | - name: git-repo
31 | from: "{{steps.checkout.outputs.artifacts.source}}"
32 | parameters:
33 | - name: image-repo
34 | value: "{{workflow.parameters.image-repo}}"
35 | - name: image-tag
36 | value: "{{steps.checkout.outputs.parameters.tag}}"
37 | - - name: image-scan
38 | template: image-scan
39 | arguments:
40 | parameters:
41 | - name: image-repo
42 | value: "{{workflow.parameters.image-repo}}"
43 | - name: image-tag
44 | value: "{{steps.checkout.outputs.parameters.tag}}"
45 | - name: central
46 | value: "{{workflow.parameters.central}}"
47 | - - name: image-check
48 | template: image-check
49 | arguments:
50 | parameters:
51 | - name: image-tag
52 | value: "{{steps.checkout.outputs.parameters.tag}}"
53 | - name: image-repo
54 | value: "{{workflow.parameters.image-repo}}"
55 | - name: central
56 | value: "{{workflow.parameters.central}}"
57 | - - name: update-deployment
58 | template: update-deployment
59 | arguments:
60 | parameters:
61 | - name: image-tag
62 | value: "{{steps.checkout.outputs.parameters.tag}}"
63 | - name: image-repo
64 | value: "{{workflow.parameters.image-repo}}"
65 | artifacts:
66 | - name: git-repo
67 | from: "{{steps.checkout.outputs.artifacts.source}}"
68 | - - name: deployment-check
69 | template: deployment-check
70 | arguments:
71 | parameters:
72 | - name: central
73 | value: "{{workflow.parameters.central}}"
74 | artifacts:
75 | - name: deployment
76 | from: "{{steps.update-deployment.outputs.artifacts.deployment}}"
77 | - name: checkout
78 | inputs:
79 | parameters:
80 | - name: git-repo-path
81 | artifacts:
82 | - name: git-repo
83 | path: /src
84 | git:
85 | repo: "{{inputs.parameters.git-repo-path}}"
86 | metadata:
87 | labels:
88 | app: argo
89 | container:
90 | image: alpine/git
91 | resources:
92 | requests:
93 | cpu: 100m
94 | memory: 100Mi
95 | limits:
96 | cpu: 400m
97 | memory: 800Mi
98 | command: [sh, -c]
99 | args: ["cd /src && git rev-parse --short HEAD > /tmp/git-commit"]
100 | outputs:
101 | artifacts:
102 | - name: source
103 | path: /src
104 | parameters:
105 | - name: tag
106 | valueFrom:
107 | path: /tmp/git-commit
108 | - name: build-push-docker
109 | inputs:
110 | artifacts:
111 | - name: git-repo
112 | path: /src
113 | parameters:
114 | - name: image-tag
115 | - name: image-repo
116 | metadata:
117 | labels:
118 | app: argo
119 | container:
120 | image: gcr.io/kaniko-project/executor:debug
121 | workingDir: /src
122 | command: ["/kaniko/executor"]
123 | args: [
124 | '--context', '/src', '--dockerfile', '/src/full.Dockerfile', '--destination',
125 | "{{inputs.parameters.image-repo}}:{{inputs.parameters.image-tag}}"
126 | ]
127 | volumeMounts:
128 | - name: regcred
129 | mountPath: /kaniko/.docker
130 | - name: image-scan
131 | inputs:
132 | parameters:
133 | - name: image-tag
134 | - name: image-repo
135 | - name: central
136 | metadata:
137 | labels:
138 | app: argo
139 | container:
140 | image: stackrox.io/roxctl:3.0.50.0
141 | volumeMounts:
142 | - name: api-token
143 | mountPath: /api-token
144 | command: ["/roxctl"]
145 | args: ["image", "scan", "--image", "{{inputs.parameters.image-repo}}:{{inputs.parameters.image-tag}}", "-e", "{{inputs.parameters.central}}", "--token-file", "/api-token/data"]
146 |
147 | - name: image-check
148 | inputs:
149 | parameters:
150 | - name: image-tag
151 | - name: image-repo
152 | - name: central
153 | metadata:
154 | labels:
155 | app: argo
156 | container:
157 | image: stackrox.io/roxctl:3.0.50.0
158 | volumeMounts:
159 | - name: api-token
160 | mountPath: /api-token
161 | command: ["/roxctl"]
162 | args: [
163 | "image", "check", "--image", "{{inputs.parameters.image-repo}}:{{inputs.parameters.image-tag}}",
164 | "-e", "{{inputs.parameters.central}}", "--token-file", "/api-token/data", "--json"
165 | ]
166 |
167 | - name: update-deployment
168 | inputs:
169 | artifacts:
170 | - name: git-repo
171 | path: /src
172 | parameters:
173 | - name: image-tag
174 | - name: image-repo
175 | metadata:
176 | labels:
177 | app: argo
178 | container:
179 | image: alpine
180 | command: [/bin/sh, -c]
181 | args: ["sed s#%IMAGE%#{{inputs.parameters.image-repo}}:{{inputs.parameters.image-tag}}#g /src/deployment.yaml > /tmp/deployment.yaml"]
182 | outputs:
183 | artifacts:
184 | - name: deployment
185 | path: /tmp/deployment.yaml
186 |
187 | - name: deployment-check
188 | inputs:
189 | parameters:
190 | - name: central
191 | artifacts:
192 | - name: deployment
193 | path: /tmp/deployment.yaml
194 | metadata:
195 | labels:
196 | app: argo
197 | container:
198 | image: stackrox.io/roxctl:3.0.50.0
199 | volumeMounts:
200 | - name: api-token
201 | mountPath: /api-token
202 | command: ["/roxctl"]
203 | args: ["deployment", "check", "--file", "/tmp/deployment.yaml", "-e", "{{inputs.parameters.central}}", "--token-file", "/api-token/data"]
204 |
205 | imagePullSecrets:
206 | - name: stackrox-io
207 | ttlStrategy:
208 | secondsAfterCompletion: 3600
209 | volumes:
210 | - name: regcred
211 | secret:
212 | secretName: regcred
213 | - name: api-token
214 | secret:
215 | secretName: rox-api
216 |
217 |
218 |
--------------------------------------------------------------------------------
/ci/function/Google Function/CI integration sample/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # StackRox Google Function scan sample
2 | # author neil@stackrox.com
3 |
4 | version: 2.1
5 | jobs:
6 | scan:
7 | docker:
8 | - image: cimg/base:2020.10
9 | steps:
10 | - run: |
11 | ROX_RETURN=$(curl -L -H "Authorization: Bearer $GOOG_API_TOKEN" https://<>.cloudfunctions.net/roxctl_image_check \
12 | --silent --fail --show-error \
13 | --header "Content-Type: application/json" \
14 | --request POST \
15 | --data "{\"rox_central_endpoint\": \"$ROX_CENTRAL_ENDPOINT\",\"rox_api_token\": \"$ROX_API_TOKEN\",\"rox_image\": \"mysql:5.6.30\"}")
16 | echo $ROX_RETURN | jq --raw-output '.output'
17 | if [ "$(echo $ROX_RETURN | jq --raw-output '.build')" = "fail" ]; then
18 | exit 1
19 | fi
20 |
21 | # This uses cURL to execute the Google Cloud Function. The function returns JSON with pass/fail and the output.
22 | # We echo the output and, finally, if the result is fail, exit with a non-zero return code to fail the build
23 |
24 | # Replace https://<> with the appropriate location of the Google Cloud Function.
25 |
26 | # Parameters for the StackRox Central and authentication to the Google Cloud Function are configured as environment variables
27 | # in CircleCI.
28 | #
29 | # `GOOG_API_TOKEN`: A Bearer token for access to the roxctl_image_check function
30 | # `ROX_CENTRAL_ENDPOINT`: the hostname/IP and port for Central (`central.stackrox.com:443`)
31 | # `ROX_API_TOKEN`: an API token from Central with at least CI privileges
32 |
33 | workflows:
34 | scanimage:
35 | when: always
36 | jobs:
37 | - scan:
38 | name: scan
--------------------------------------------------------------------------------
/ci/function/Google Function/README.md:
--------------------------------------------------------------------------------
1 | # Google Function CI Scan Sample
2 |
3 |
4 | This sample uses a Google Cloud Function to scan an image and return results. This is useful for scanning builds in hosted CI solutions when Central is not accessible from the Internet -- the function can be used as a proxy.
5 |
6 | The `roxctl_image_check` directory has the sample Python function. This script takes an HTTP POST with a JSON body containing the parameters and returns a pass/fail and the policy check output.
7 |
8 | Args:
9 | JSON array with
10 | `rox_central_endpoint` -- the hostname/IP and port for Central (`central.stackrox.com:443`)
11 | `rox_api_token` -- an API token from Central with at least CI privileges
12 | `rox_image` -- the image to scan (`registry.stackrox.local/frontend:1.5.1`)
13 | Returns:
14 | JSON array with
15 | `build` -- either `pass` or `fail` to indicate if any policies are enforced
16 | `output` -- the output of `roxctl image check`
17 |
18 | The `CI Integration sample` directory contains a sample CI integration for consuming this function in a CircleCI build pipeline.
19 |
20 | OWNER: neilcar
21 |
22 | LATEST TESTED: 3.0.52.0
--------------------------------------------------------------------------------
/ci/function/Google Function/roxctl_image_check/main.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import os
4 | import stat
5 | import subprocess
6 |
7 | def image_check(request):
8 | """Checks an image with roxctl
9 | Args:
10 | JSON array with
11 | `rox_central_endpoint` -- the hostname/IP and port for Central (`central.stackrox.com:443`)
12 | `rox_api_token` -- an API token from Central with at least CI privileges
13 | `rox_image` -- the image to scan (`registry.stackrox.local/frontend:1.5.1`)
14 | Returns:
15 | JSON array with
16 | `build` -- either `pass` or `fail` to indicate if any policies are enforced
17 | `output` -- the output of `roxctl image check`
18 | """
19 | request_json = request.get_json()
20 |
21 | rox_central_endpoint = request_json['rox_central_endpoint']
22 | rox_api_token = request_json['rox_api_token']
23 | rox_image = request_json['rox_image']
24 |
25 | print("Using roxctl to scan image: " + rox_image)
26 |
27 | download_roxctl(rox_central_endpoint, rox_api_token)
28 |
29 | out,err = roxctl_image_check(rox_central_endpoint, rox_api_token, rox_image)
30 |
31 | if err == 0:
32 | err_text = "pass"
33 | else:
34 | err_text = "fail"
35 |
36 | json_return = {"build": err_text, "output": out.decode("utf-8")}
37 |
38 | return json.dumps(json_return)
39 |
40 | def download_roxctl(rox_central_endpoint, rox_api_token):
41 | url = "https://" + rox_central_endpoint + "/api/cli/download/roxctl-linux"
42 | token = "Bearer " + rox_api_token
43 | print("token: " + token)
44 | headers = {'Authorization': token}
45 | r = requests.get(url, headers=headers)
46 | open('/tmp/roxctl', 'wb').write(r.content)
47 | st = os.stat('/tmp/roxctl')
48 | os.chmod('/tmp/roxctl', st.st_mode | stat.S_IEXEC)
49 |
50 |
51 | def roxctl_image_check(rox_central_endpoint, rox_api_token, rox_image):
52 | os.environ["ROX_API_TOKEN"] = rox_api_token
53 | roxctl = subprocess.Popen(['/tmp/roxctl', 'image', 'check', '-e', rox_central_endpoint, '--image', rox_image],
54 | stdout=subprocess.PIPE,
55 | stderr=subprocess.STDOUT)
56 | out, err = roxctl.communicate()
57 | return out, roxctl.returncode
--------------------------------------------------------------------------------
/ci/function/Google Function/roxctl_image_check/requirements.txt:
--------------------------------------------------------------------------------
1 | # Function dependencies, for example:
2 | # package>=version
3 |
4 | requests
5 |
--------------------------------------------------------------------------------
/completions/fish/roxctl.fish:
--------------------------------------------------------------------------------
1 | # Command Sets
2 | set -l base_commands central cluster collector deployment helm help image scanner sensor version
3 | set -l central_commands backup cert db debug generate init-bundles license userpki whoami
4 | set -l image_commands check scan
5 | set -l deployment_commands check
6 | set -l scanner_commands generate upload-db
7 | set -l sensor_commands generate generate-certs get-bundle
8 |
9 | # Disable file completions
10 | complete -c roxctl -f
11 |
12 | # Base flags
13 | complete -c roxctl -s h -l help -d "more information about a command"
14 | complete -c roxctl -s e -l endpoint -d "endpoint for service to contact"
15 | complete -c roxctl -l insecure -d "skip tls certification validation"
16 | complete -c roxctl -s p -l password -d "password for basic auth"
17 | complete -c roxctl -s e -l endpoint -d "stackrox central endpoint"
18 | complete -c roxctl -l token-file -d "use API token in the provided file"
19 |
20 |
21 | # Base commands
22 | complete -c roxctl -n "not __fish_seen_subcommand_from $base_commands" -a "$base_commands"
23 |
24 | # Central subcommands
25 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "backup" -d "backup the StackRox database and certificates"
26 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "cert" -d "download certificate chain for the Central service"
27 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "db" -d "commands related to the StackRox database"
28 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "debug" -d "debug the Central Service"
29 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "generate" -d "generate k8s manifests to deploy StackRox Central"
30 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "init-bundles" -d "manage cluster init bundle"
31 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "license" -d "add and display license information"
32 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "userpki" -d "manage user certificate authorization providers"
33 | complete -c roxctl -n "__fish_seen_subcommand_from central; and not __fish_seen_subcommand_from $central_commands" -a "whoami" -d "info about the current user"
34 |
35 | # Image flags
36 | complete -c roxctl -n "__fish_seen_subcommand_from $image_commands" -s t -l timeout -d "timeout for api requests (default 10m0s)"
37 | complete -c roxctl -n "__fish_seen_subcommand_from $image_commands" -s i -l image -d "image name and tag" -a "(docker image list --format '{{.Repository}}:{{.Tag}}')"
38 | complete -c roxctl -n "__fish_seen_subcommand_from $image_commands" -s a -l include-snoozed -d "return both snoozed and unsnoozed CVEs if set to false"
39 |
40 | # Image subcommands
41 | complete -c roxctl -n "__fish_seen_subcommand_from image; and not __fish_seen_subcommand_from $image_commands" -a "check" -d "check images for build time policy violations"
42 | complete -c roxctl -n "__fish_seen_subcommand_from image; and not __fish_seen_subcommand_from $image_commands" -a "scan" -d "scan the specified images"
43 |
44 | # Deployment flags
45 | complete -c roxctl -n "__fish_seen_subcommand_from $deployment_commands" -s t -l timeout -d "timeout for api requests (default 10m0s)"
46 | complete -c roxctl -n "__fish_seen_subcommand_from $deployment_commands" -s f -l file -d "evaluate policies against yaml file" -a "(find . | grep -i -e '\.y\(aml\|ml\)' | head -n 10 | sort -d -u)"
47 |
48 |
49 | # Deployment subcommands
50 | complete -c roxctl -n "__fish_seen_subcommand_from deployment; and not __fish_seen_subcommand_from $deployment_commands" -a "check" -d "check deployments for deploy time policy violations"
51 |
52 | # Scanner flags
53 | complete -c roxctl -n "__fish_seen_subcommand_from $scanner_commands" -s t -l timeout -d "timeout for api requests (default 10m0s)"
54 |
55 | # Scanner subcommands
56 | complete -c roxctl -n "__fish_seen_subcommand_from scanner; and not __fish_seen_subcommand_from $scanner_commands" -a "generate" -d "generate k8s manifests to deploy StackRox Scanner"
57 | complete -c roxctl -n "__fish_seen_subcommand_from scanner; and not __fish_seen_subcommand_from $scanner_commands" -a "upload-db" -d "upload a vulnerability database for the StackRox Scanner"
58 |
59 | # Sensor flags
60 | complete -c roxctl -n "__fish_seen_subcommand_from $sensor_commands" -s t -l timeout -d "timeout for api requests (default 10m0s)"
61 |
62 | # Sensor subcommands
63 | complete -c roxctl -n "__fish_seen_subcommand_from sensor; and not __fish_seen_subcommand_from $sensor_commands" -a "generate" -d "generate k8s manifests to deploy StackRox services into secured clusters"
64 | complete -c roxctl -n "__fish_seen_subcommand_from sensor; and not __fish_seen_subcommand_from $sensor_commands" -a "generate-certs" -d "download a YAML file with renewed certificates"
65 | complete -c roxctl -n "__fish_seen_subcommand_from sensor; and not __fish_seen_subcommand_from $sensor_commands" -a "get-bundle" -d "download a bundle with the files to deploy StackRox services into a cluster"
66 |
67 |
68 |
--------------------------------------------------------------------------------
/compliance/scan-compliance.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | set -euo pipefail
4 |
5 | if [[ -z $ROX_API_TOKEN ]]; then
6 | echo "ROX_API_TOKEN needs to be set" 1>&2
7 | exit 1
8 | fi
9 |
10 | if [[ -z "$ROX_ENDPOINT" ]]; then
11 | echo "ROX_ENDPOINT needs to be set" 1>&2
12 | exit 1
13 | fi
14 |
15 | if [ ! -x "$(which jq)" ]; then
16 | echo "jq is a required for this script to work correctly" 1>&2
17 | exit 1
18 | fi
19 |
20 | function roxcurl() {
21 | curl -sk -H "Authorization: Bearer $ROX_API_TOKEN" "$@"
22 | }
23 |
24 | cluster_ids=$(roxcurl "$ROX_ENDPOINT/v1/clusters" | jq -r .clusters[].id)
25 | for cluster in $cluster_ids; do
26 | echo "Triggering compliance run for cluster $cluster"
27 | runs=$(roxcurl "$ROX_ENDPOINT/v1/compliancemanagement/runs" -X POST -d '{ "selection": { "cluster_id": "'"$cluster"'", "standard_id": "*" } }')
28 | run_ids=$(jq -r .startedRuns[].id <<< "$runs")
29 | num_runs=$(jq '.startedRuns | length' <<< "$runs")
30 | while true; do
31 | size="$num_runs"
32 | for run_id in $run_ids; do
33 | run_status=$(roxcurl "$ROX_ENDPOINT/v1/compliancemanagement/runstatuses" --data-urlencode "run_ids=$run_id" | jq -r .runs[0])
34 | run_state=$(jq -r .state <<< "$run_status")
35 | standard=$(jq -r .standardId <<< "$run_status")
36 | echo "Run $run_id for cluster $cluster and standard $standard has state $run_state"
37 | if [[ "$run_state" == "FINISHED" ]]; then
38 | size=$(( size - 1))
39 | fi
40 | done
41 | if [[ "$size" == 0 ]]; then
42 | echo "Compliance for cluster $cluster has completed"
43 | break
44 | fi
45 | sleep 5
46 | done
47 | done
48 |
--------------------------------------------------------------------------------
/guides/cloud-provider-integrations/azure-service-principal-m2m-auth.md:
--------------------------------------------------------------------------------
1 | ## Using Azure Entra ID service principals for machine to machine auth with ACS
2 |
3 | **Note:** Instructions provided in this guide are provided as-is without warranty or support from Red Hat.
4 |
5 | ### 1. Create Azure service principal
6 |
7 | For this, we can use [the following guide from Microsoft Learn](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal?source=recommendations#register-an-application-with-microsoft-entra-id-and-create-a-service-principal).
8 |
9 | The only step: “**Register an application with Microsoft Entra ID and create a service principal”** is required. We do not have to add roles for that service principal because it does not have to access any Azure resource. It will be used only for authentication in ACS.
10 |
11 | ### 2. Setup authentication for created service principal
12 |
13 | This is required in order for the service principal to authenticate to Azure.
14 |
15 | We can use [the following steps from the same Microsoft Learn page](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal?source=recommendations#set-up-authentication).
16 |
17 | After authentication setup, we can use the `az` command to log into Azure and retrieve the access token required to do m2m authentication to ACS.
18 |
19 | ### 3. Login with `az`
20 |
21 | This example uses a secret to authenticate (**Option 3** in the “Setup authentication” guide mentioned under step 2.).
22 |
23 | ```
24 | az login --service-principal \
25 | --username \
26 | --password \
27 | --tenant \
28 | --allow-no-subscriptions
29 | ```
30 |
31 | It is important to use the `--allow-no-subscriptions` flag if the service principal does not have any roles.
32 |
33 | **Note:** Logging as a regular user with `az login` would also work. In that case, the difference would be that we need to use `unique_name` or another claim from the token during the configuration of ACS machine access (Step 4\. below)
34 |
35 | After this, the command:
36 |
37 | ```
38 | az account list --output yamlc
39 | ```
40 |
41 | Should output account with `user` property. The name of that user should be the service principal ID.
42 |
43 | ```
44 | user:
45 | name:
46 | type: servicePrincipal
47 | ```
48 |
49 | ### 4. Configure ACS
50 |
51 | You can follow [Configuring short-lived access documentation on Red Hat documentation](https://docs.redhat.com/en/documentation/red_hat_advanced_cluster_security_for_kubernetes/4.6/html/operating/managing-user-access#configure-short-lived-access). *Ensure to use documentation from used ACS version.*
52 |
53 | Create a **Machine access configuration** - with the following fields:
54 |
55 | Issuer: `https://sts.windows.net//`
56 |
57 | Add a rule with:
58 | Key: `appid`
59 | Value: ``
60 |
61 | **Important:** ACS has to be able to access: `https://sts.windows.net//.well-known/openid-configuration`
62 |
63 | ### 5. Test everything
64 |
65 | Use the following `roxctl` command:
66 |
67 | ```
68 | roxctl central machine-to-machine exchange \
69 | --token="$(az account get-access-token --tenant "" --query "accessToken" --output tsv)"
70 | ```
71 |
72 | *If `--output tsv` does not provide valid token format. There is option to use JSON output and `jq` command to select token from payload.*
73 |
74 | After successful login, running: `roxctl central whoami` should output ACS authentication information. And “User name:” in the output should be the same as provided `` in the `az` login command.
75 |
--------------------------------------------------------------------------------
/ingress/contour/central-ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: projectcontour.io/v1
2 | kind: HTTPProxy
3 | metadata:
4 | name: central
5 | namespace: stackrox
6 | spec:
7 | tcpproxy:
8 | services:
9 | - name: central
10 | port: 443
11 | virtualhost:
12 | fqdn: central.blah.blar.tld
13 | tls:
14 | passthrough: true
15 |
--------------------------------------------------------------------------------
/ingress/haproxy/Readme.md:
--------------------------------------------------------------------------------
1 | # HAProxy Ingress configuration for StackRox Central
2 |
3 | This configuration provides a simple HAProxy ssl-passthrough ingress for StackRox Central.
4 |
5 | ## Files
6 | * `central-hap-ingress.yaml` The central-ingress definition for the stackrox namespace
7 | * `haproxy-controller.yaml` Example HAProxy controller configuration with ssl-passthrough enabled. If you're running HAProxy controller already, you'll probably only need the lines from the ConfigMap section to enable ssl-passthrough.
8 |
--------------------------------------------------------------------------------
/ingress/haproxy/central-hap-ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1beta1
2 | kind: Ingress
3 | metadata:
4 | name: central-ingress
5 | namespace: stackrox
6 | annotations:
7 | ingress.kubernetes.io/ssl-passthrough: "true"
8 | spec:
9 | tls:
10 | - hosts:
11 | - central.example.com
12 | rules:
13 | - host: central.example.com
14 | http:
15 | paths:
16 | - backend:
17 | serviceName: central
18 | servicePort: 443
19 |
--------------------------------------------------------------------------------
/ingress/haproxy/haproxy-controller.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Namespace
4 | metadata:
5 | name: haproxy-controller
6 |
7 | ---
8 | apiVersion: v1
9 | kind: ServiceAccount
10 | metadata:
11 | name: haproxy-ingress-service-account
12 | namespace: haproxy-controller
13 |
14 | ---
15 | kind: ClusterRole
16 | apiVersion: rbac.authorization.k8s.io/v1
17 | metadata:
18 | name: haproxy-ingress-cluster-role
19 | rules:
20 | - apiGroups:
21 | - ""
22 | resources:
23 | - configmaps
24 | - endpoints
25 | - nodes
26 | - pods
27 | - services
28 | - namespaces
29 | - events
30 | - serviceaccounts
31 | verbs:
32 | - get
33 | - list
34 | - watch
35 | - apiGroups:
36 | - "extensions"
37 | resources:
38 | - ingresses
39 | - ingresses/status
40 | verbs:
41 | - get
42 | - list
43 | - watch
44 | - apiGroups:
45 | - ""
46 | resources:
47 | - secrets
48 | verbs:
49 | - get
50 | - list
51 | - watch
52 | - create
53 | - patch
54 | - update
55 | - apiGroups:
56 | - extensions
57 | resources:
58 | - ingresses
59 | verbs:
60 | - get
61 | - list
62 | - watch
63 |
64 | ---
65 | kind: ClusterRoleBinding
66 | apiVersion: rbac.authorization.k8s.io/v1
67 | metadata:
68 | name: haproxy-ingress-cluster-role-binding
69 | namespace: haproxy-controller
70 | roleRef:
71 | apiGroup: rbac.authorization.k8s.io
72 | kind: ClusterRole
73 | name: haproxy-ingress-cluster-role
74 | subjects:
75 | - kind: ServiceAccount
76 | name: haproxy-ingress-service-account
77 | namespace: haproxy-controller
78 |
79 | ---
80 | apiVersion: v1
81 | kind: ConfigMap
82 | metadata:
83 | name: haproxy
84 | namespace: haproxy-controller
85 | data:
86 | ssl-passthrough: "true"
87 |
88 | ---
89 | apiVersion: apps/v1
90 | kind: Deployment
91 | metadata:
92 | labels:
93 | run: ingress-default-backend
94 | name: ingress-default-backend
95 | namespace: haproxy-controller
96 | spec:
97 | replicas: 1
98 | selector:
99 | matchLabels:
100 | run: ingress-default-backend
101 | template:
102 | metadata:
103 | labels:
104 | run: ingress-default-backend
105 | spec:
106 | containers:
107 | - name: ingress-default-backend
108 | image: gcr.io/google_containers/defaultbackend:1.0
109 | ports:
110 | - containerPort: 8080
111 |
112 | ---
113 | apiVersion: v1
114 | kind: Service
115 | metadata:
116 | labels:
117 | run: ingress-default-backend
118 | name: ingress-default-backend
119 | namespace: haproxy-controller
120 | spec:
121 | selector:
122 | run: ingress-default-backend
123 | ports:
124 | - name: port-1
125 | port: 8080
126 | protocol: TCP
127 | targetPort: 8080
128 |
129 | ---
130 | apiVersion: apps/v1
131 | kind: Deployment
132 | metadata:
133 | labels:
134 | run: haproxy-ingress
135 | name: haproxy-ingress
136 | namespace: haproxy-controller
137 | spec:
138 | replicas: 1
139 | selector:
140 | matchLabels:
141 | run: haproxy-ingress
142 | template:
143 | metadata:
144 | labels:
145 | run: haproxy-ingress
146 | spec:
147 | serviceAccountName: haproxy-ingress-service-account
148 | containers:
149 | - name: haproxy-ingress
150 | image: haproxytech/kubernetes-ingress
151 | args:
152 | - --configmap=haproxy-controller/haproxy
153 | - --default-backend-service=haproxy-controller/ingress-default-backend
154 | resources:
155 | requests:
156 | cpu: "500m"
157 | memory: "50Mi"
158 | livenessProbe:
159 | httpGet:
160 | path: /healthz
161 | port: 1042
162 | ports:
163 | - name: http
164 | containerPort: 80
165 | - name: https
166 | containerPort: 443
167 | - name: stat
168 | containerPort: 1024
169 | env:
170 | - name: TZ
171 | value: "Etc/UTC"
172 | - name: POD_NAME
173 | valueFrom:
174 | fieldRef:
175 | fieldPath: metadata.name
176 | - name: POD_NAMESPACE
177 | valueFrom:
178 | fieldRef:
179 | fieldPath: metadata.namespace
180 |
181 | ---
182 | apiVersion: v1
183 | kind: Service
184 | metadata:
185 | labels:
186 | run: haproxy-ingress
187 | name: haproxy-ingress
188 | namespace: haproxy-controller
189 | spec:
190 | selector:
191 | run: haproxy-ingress
192 | type: LoadBalancer
193 | ports:
194 | - name: http
195 | port: 80
196 | protocol: TCP
197 | targetPort: 80
198 | - name: https
199 | port: 443
200 | protocol: TCP
201 | targetPort: 443
202 | - name: stat
203 | port: 1024
204 | protocol: TCP
205 | targetPort: 1024
206 |
--------------------------------------------------------------------------------
/ingress/istio-gw/Readme.md:
--------------------------------------------------------------------------------
1 | # Istio Gateway Ingress configuration for StackRox Central
2 |
3 | This configuration provides a simple Istio Gateway tls-passthrough ingress for StackRox Central. Tested on Istio v1.8.
4 |
5 | ## Notes
6 | * By default, Istio's Ingress Gateway creates a loadbalancer service. You can see the assigned IP or hostname using `kubectl -n istio-system get svc`
7 | * Routing to appropriate backend depends on DNS. This YAML uses `central.example.com` which should be customized for your environment
8 |
9 | ## Files
10 | * `central-istio-gw-passthrough.yaml` The Gateway, VirtualService, and DestinationRule definitions for the stackrox namespace
11 |
12 | OWNER: srcporter
13 |
14 | LAST TESTED VERSION: 3.0.52.1
15 |
--------------------------------------------------------------------------------
/ingress/istio-gw/central-istio-gw-passthrough.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.istio.io/v1alpha3
2 | kind: DestinationRule
3 | metadata:
4 | name: central
5 | namespace: stackrox
6 | spec:
7 | host: central.stackrox
8 | trafficPolicy:
9 | loadBalancer:
10 | simple: LEAST_CONN
11 | ---
12 | apiVersion: networking.istio.io/v1alpha3
13 | kind: Gateway
14 | metadata:
15 | name: central-gateway
16 | namespace: stackrox
17 | spec:
18 | selector:
19 | istio: ingressgateway # use Istio default gateway implementation
20 | servers:
21 | - port:
22 | number: 443
23 | name: https
24 | protocol: TLS
25 | tls:
26 | mode: PASSTHROUGH
27 | hosts:
28 | - "central.example.com"
29 | ---
30 | apiVersion: networking.istio.io/v1alpha3
31 | kind: VirtualService
32 | metadata:
33 | name: central
34 | namespace: stackrox
35 | spec:
36 | hosts:
37 | - central.example.com
38 | gateways:
39 | - central-gateway
40 | tls:
41 | - match:
42 | - port: 443
43 | sniHosts:
44 | - central.example.com
45 | route:
46 | - destination:
47 | host: central
48 | port:
49 | number: 443
50 |
51 |
--------------------------------------------------------------------------------
/ingress/nginx/Readme.md:
--------------------------------------------------------------------------------
1 | # Nginx Ingress configuration for StackRox Central
2 |
3 | This configuration provides two examples for Kubernetes Nginx Ingress
4 |
5 | Note that these apply to the open-source [Kubernetes nginx ingress](https://kubernetes.github.io/ingress-nginx/) and **not** the nginx plus family of products.
6 |
7 | ## Files
8 | * `central-nginx-passthrough-ingress.yaml` Central-ingress definition for the stackrox namespace that uses ssl-passthrough.
9 | * `central-nginx-encrypt-ingress.yaml` Central-ingress that terminates TLS at nginx, and re-encrypts to the Central service. Customization of hostnames and certificate secrets is recommended.
10 |
11 |
12 | NOTE: in order to use the ssl-passthrough annotation and have it work correctly, the nginx ingress controller must be deployed with the `--enable-ssl-passthrough` option.
13 |
14 | Please review the [documentation for TLS/HTTPS](https://kubernetes.github.io/ingress-nginx/user-guide/tls/#ssl-passthrough) on nginx ingress.
15 |
16 | In a standard installation of the ingress controller you can add this to a running pod with:
17 |
18 | `kubectl edit nginx-ingress-controller -n ingress-nginx`
19 |
20 | Change the containers spec for the controller to add the --enable-ssl-passthrough argument:
21 |
22 | spec:
23 | containers:
24 | - args:
25 | - /nginx-ingress-controller
26 | - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
27 | - --election-id=ingress-controller-leader
28 | - --ingress-class=nginx
29 | - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
30 | - --validating-webhook=:8443
31 | - --validating-webhook-certificate=/usr/local/certificates/cert
32 | - --validating-webhook-key=/usr/local/certificates/key
33 | - --enable-ssl-passthrough
34 |
35 | OWNER: srcporter
36 | LAST TESTED VERSION: 3.0.54.0
37 |
--------------------------------------------------------------------------------
/ingress/nginx/central-nginx-encrypt-ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: extensions/v1beta1
2 | kind: Ingress
3 | metadata:
4 | annotations:
5 | kubernetes.io/ingress.class: "nginx"
6 | nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"
7 | nginx.ingress.kubernetes.io/proxy-body-size: "0"
8 | name: central-ingress
9 | namespace: stackrox
10 | spec:
11 | rules:
12 | - host: central.example.com
13 | http:
14 | paths:
15 | - backend:
16 | serviceName: central
17 | servicePort: 443
18 | tls:
19 | - secretName: central-default-tls-cert
20 | hosts:
21 | - central.example.com
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ingress/nginx/central-nginx-passthrough-ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: extensions/v1beta1
2 | kind: Ingress
3 | metadata:
4 | name: central-ingress
5 | annotations:
6 | nginx.ingress.kubernetes.io/ssl-passthrough: "true"
7 | nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"
8 | namespace: stackrox
9 | spec:
10 | rules:
11 | - http:
12 | paths:
13 | - path: /
14 | backend:
15 | serviceName: central
16 | servicePort: 443
17 |
--------------------------------------------------------------------------------
/ingress/traefik/Readme.md:
--------------------------------------------------------------------------------
1 | # Traefik ingress configuration for StackRox Central
2 |
3 | This configuration provides a Traefik ingress definition for StackRox central which terminates TLS at the Ingress and connects to Central over TLS
4 |
5 | ## Traefik config
6 | * Strongly recommended that Traefik be configured to accept TLS connections at the *frontend*. In the ingress example here, the TLS certificate presented by Traefik is in the secret `stackrox-central-tls`. This certificate can be self-signed or publicly signed, but must be compatible with the requirements that Traefik documents at https://doc.traefik.io/traefik/v1.7/user-guide/kubernetes/#add-a-tls-certificate-to-the-ingress
7 | * In order to make a TLS connection to StackRox Central on the *backend*, the certificate used by central must either be signed by a trusted root (recommended), or Traefik must be configured with the --insecureskipverify option.
8 | * Traefik configurations with TLS router can avoid the certificate configuration with the passthrough option https://doc.traefik.io/traefik/routing/routers/#passthrough
9 |
10 | ## Notes
11 | * Note that if you use a self-signed certificate for the any Ingress frontend, StackRox Sensors in remote clusters must be configured to trust that certificate https://help.stackrox.com/docs/configure-stackrox/configure-custom-certificates/#configure-sensor-to-trust-custom-certificates
12 | * Routing to appropriate backend depends on DNS. This YAML uses `central.example.com` which should be customized for your environment
13 |
14 | ## Files
15 | * `central-traefik-ingress.yaml` Central Ingress definition for Traefik
16 |
17 | OWNER: srcporter
18 |
19 | LAST TESTED VERSION: 3.0.53.0
20 |
--------------------------------------------------------------------------------
/ingress/traefik/central-traefik-ingress.yaml:
--------------------------------------------------------------------------------
1 | kind: Ingress
2 | apiVersion: extensions/v1beta1
3 | metadata:
4 | name: central-ingress
5 | namespace: stackrox
6 |
7 | spec:
8 | rules:
9 | - host: central.example.com
10 | http:
11 | paths:
12 | - path: /
13 | backend:
14 | serviceName: central
15 | servicePort: 443
16 | tls:
17 | - secretName: stackrox-central-tls
18 |
19 |
--------------------------------------------------------------------------------
/policies/CVE-2021-4034-build-deploy.json:
--------------------------------------------------------------------------------
1 | {
2 | "policies": [
3 | {
4 | "name": "PwnKit: CVE-2021-4034 - Polkit local privilege escalation vulnerability",
5 | "description": "Alert on deployments with images containing the PwnKit vulnerability (CVE-2021-4034). This is a local privilege escalation vulnerability impacting the pkexec binary.",
6 | "rationale": "This vulnerability allows an unprivileged local attacker to escalate privileges, bypassing any authentication and policies due to incorrect handling of the process argument vector.",
7 | "remediation": "Update the polkit package to 0.112-26.el7_9.1 (for RHEL 7-based container images) or polkit-0.115-13.el8_5.1 (for RHEL 8-based container images).",
8 | "disabled": false,
9 | "categories": [
10 | "Vulnerability Management"
11 | ],
12 | "fields": null,
13 | "lifecycleStages": [
14 | "BUILD",
15 | "DEPLOY"
16 | ],
17 | "eventSource": "NOT_APPLICABLE",
18 | "whitelists": [],
19 | "exclusions": [],
20 | "scope": [],
21 | "severity": "CRITICAL_SEVERITY",
22 | "enforcementActions": [],
23 | "notifiers": [],
24 | "lastUpdated": null,
25 | "SORTName": "",
26 | "SORTLifecycleStage": "",
27 | "SORTEnforcement": false,
28 | "policyVersion": "1.1",
29 | "policySections": [
30 | {
31 | "sectionName": "",
32 | "policyGroups": [
33 | {
34 | "fieldName": "CVE",
35 | "booleanOperator": "OR",
36 | "negate": false,
37 | "values": [
38 | {
39 | "value": "CVE-2021-4034"
40 | }
41 | ]
42 | }
43 | ]
44 | }
45 | ],
46 | "mitreAttackVectors": [],
47 | "criteriaLocked": true,
48 | "mitreVectorsLocked": true,
49 | "isDefault": false
50 | }
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/policies/CVE-2021-44228-build-deploy.json:
--------------------------------------------------------------------------------
1 | {
2 | "policies": [
3 | {
4 | "name": "Log4Shell: CVE-2021-44228 - log4j Remote Code Execution vulnerability",
5 | "description": "Alert on deployments with images containing the Log4Shell vulnerability (CVE-2021-44228). This is a flaw in the Java logging library Apache Log4j in versions from 2.0.0 and before as well as version 2.14.1.",
6 | "rationale": "This vulnerability allows a remote attacker to execute code on the server if the system logs an attacker-controlled string value with the attacker's JNDI LDAP server lookup.",
7 | "remediation": "Update the log4j libary to version 2.15.0 (which disables the feature by default), 2.16.0 (which removes the functionality) or later. If not possible to upgrade, there are two possible mitigations for this flaw in versions from 2.10 to 2.14.1: Set the system property log4j2.formatMsgNoLookups to true, or remove the JndiLookup class from the classpath.",
8 | "disabled": false,
9 | "categories": [
10 | "Vulnerability Management"
11 | ],
12 | "fields": null,
13 | "lifecycleStages": [
14 | "BUILD",
15 | "DEPLOY"
16 | ],
17 | "eventSource": "NOT_APPLICABLE",
18 | "whitelists": [],
19 | "exclusions": [],
20 | "scope": [],
21 | "severity": "CRITICAL_SEVERITY",
22 | "enforcementActions": [],
23 | "notifiers": [],
24 | "lastUpdated": null,
25 | "SORTName": "",
26 | "SORTLifecycleStage": "",
27 | "SORTEnforcement": false,
28 | "policyVersion": "1.1",
29 | "policySections": [
30 | {
31 | "sectionName": "",
32 | "policyGroups": [
33 | {
34 | "fieldName": "CVE",
35 | "booleanOperator": "OR",
36 | "negate": false,
37 | "values": [
38 | {
39 | "value": "CVE-2021-44228"
40 | }
41 | ]
42 | }
43 | ]
44 | }
45 | ],
46 | "mitreAttackVectors": [],
47 | "criteriaLocked": true,
48 | "mitreVectorsLocked": true,
49 | "isDefault": true
50 | }
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/policies/leaky-vessels.json:
--------------------------------------------------------------------------------
1 | {
2 | "policies": [
3 | {
4 | "name": "Leaky Vessels: runc container breakout",
5 | "description": "CVE-2024-21626 is a vulnerability in the runc container runtime allowing an attacker to break out of the container isolation and achieve full root RCE via a crafted image that exploits an issue within the WORKDIR instruction's handling.",
6 | "rationale": "This vulnerability potentially allows an attacker to access host resources using a crafted file descriptor from the container, impacting both build and deployment operations.",
7 | "remediation": "Remove Containerfile lines resembling 'WORKDIR /proc/self/fd/[ID]' (with ID being a system dependent file descriptor)",
8 | "disabled": false,
9 | "categories": [
10 | "Anomalous Activity",
11 | "Kubernetes"
12 | ],
13 | "lifecycleStages": [
14 | "BUILD",
15 | "DEPLOY"
16 | ],
17 | "eventSource": "NOT_APPLICABLE",
18 | "exclusions": [],
19 | "scope": [],
20 | "severity": "HIGH_SEVERITY",
21 | "enforcementActions": [],
22 | "notifiers": [],
23 | "SORTName": "",
24 | "SORTLifecycleStage": "",
25 | "SORTEnforcement": false,
26 | "policyVersion": "1.1",
27 | "policySections": [
28 | {
29 | "sectionName": "Policy Section 1",
30 | "policyGroups": [
31 | {
32 | "fieldName": "Dockerfile Line",
33 | "booleanOperator": "OR",
34 | "negate": false,
35 | "values": [
36 | {
37 | "value": "WORKDIR=.*\\/proc\\/self\\/fd\\/.*"
38 | }
39 | ]
40 | }
41 | ]
42 | }
43 | ],
44 | "mitreAttackVectors": [
45 | {
46 | "tactic": "TA0004",
47 | "techniques": [
48 | "T1611"
49 | ]
50 | }
51 | ],
52 | "criteriaLocked": false,
53 | "mitreVectorsLocked": false,
54 | "isDefault": false
55 | }
56 | ]
57 | }
--------------------------------------------------------------------------------
/policies/oc-debug-runtime.json:
--------------------------------------------------------------------------------
1 | {
2 | "policies": [
3 | {
4 | "name": "Possible 'oc debug' access to pod",
5 | "description": "Detect attempts to access pods using 'oc debug'",
6 | "rationale": "'oc debug' can be used to access pod contents, potentially exposing sensitive data.",
7 | "remediation": "Review OpenShift audit logs to verify the user, and investigate whether this was legitimate trouble-shooting or malicious activity.",
8 | "disabled": false,
9 | "categories": [
10 | "Anomalous Activity"
11 | ],
12 | "lifecycleStages": [
13 | "RUNTIME"
14 | ],
15 | "eventSource": "DEPLOYMENT_EVENT",
16 | "exclusions": [],
17 | "scope": [],
18 | "severity": "HIGH_SEVERITY",
19 | "enforcementActions": [],
20 | "notifiers": [],
21 | "SORTName": "",
22 | "SORTLifecycleStage": "",
23 | "SORTEnforcement": false,
24 | "policyVersion": "1.1",
25 | "policySections": [
26 | {
27 | "sectionName": "Shell detection",
28 | "policyGroups": [
29 | {
30 | "fieldName": "Process Name",
31 | "booleanOperator": "OR",
32 | "negate": false,
33 | "values": [
34 | {
35 | "value": "^.*(sh)$"
36 | }
37 | ]
38 | },
39 | {
40 | "fieldName": "Process UID",
41 | "booleanOperator": "OR",
42 | "negate": false,
43 | "values": [
44 | {
45 | "value": "0"
46 | }
47 | ]
48 | }
49 | ]
50 | }
51 | ],
52 | "mitreAttackVectors": [],
53 | "criteriaLocked": false,
54 | "mitreVectorsLocked": false,
55 | "isDefault": false
56 | }
57 | ]
58 | }
--------------------------------------------------------------------------------
/policies/polkit-execution.json:
--------------------------------------------------------------------------------
1 | {
2 | "policies": [
3 | {
4 | "name": "Polkit Execution Detected",
5 | "description": "Detects execution of the pkexec binary in a container",
6 | "rationale": "Polkit can be abused by attackers to elevate privileges within a container.",
7 | "remediation": "Use your package manager's \"remove\" command to remove polkit packages from the image build for production containers.",
8 | "disabled": false,
9 | "categories": [
10 | "Security Best Practices"
11 | ],
12 | "lifecycleStages": [
13 | "RUNTIME"
14 | ],
15 | "eventSource": "DEPLOYMENT_EVENT",
16 | "exclusions": [],
17 | "scope": [],
18 | "severity": "MEDIUM_SEVERITY",
19 | "enforcementActions": [],
20 | "notifiers": [],
21 | "SORTName": "Polkit Execution Detected",
22 | "SORTLifecycleStage": "RUNTIME",
23 | "SORTEnforcement": false,
24 | "policyVersion": "1.1",
25 | "policySections": [
26 | {
27 | "sectionName": "",
28 | "policyGroups": [
29 | {
30 | "fieldName": "Process Name",
31 | "booleanOperator": "OR",
32 | "negate": false,
33 | "values": [
34 | {
35 | "value": "pkexec"
36 | }
37 | ]
38 | }
39 | ]
40 | }
41 | ],
42 | "mitreAttackVectors": [],
43 | "criteriaLocked": true,
44 | "mitreVectorsLocked": true,
45 | "isDefault": false
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/policies/polkit-in-image.json:
--------------------------------------------------------------------------------
1 | {
2 | "policies": [
3 | {
4 | "name": "Polkit in Image",
5 | "description": "Alert on deployments with Polkit present",
6 | "rationale": "Leaving privileged administration tools like Polkit in an image potentially allows attackers to escalate privileges within the container.",
7 | "remediation": "Use your package manager's \"remove\" command to remove polkit packages from the image build for production containers.",
8 | "disabled": false,
9 | "categories": [
10 | "Security Best Practices"
11 | ],
12 | "fields": null,
13 | "lifecycleStages": [
14 | "BUILD",
15 | "DEPLOY"
16 | ],
17 | "eventSource": "NOT_APPLICABLE",
18 | "whitelists": [],
19 | "exclusions": [],
20 | "scope": [],
21 | "severity": "LOW_SEVERITY",
22 | "enforcementActions": [],
23 | "notifiers": [],
24 | "SORTName": "",
25 | "SORTLifecycleStage": "",
26 | "SORTEnforcement": false,
27 | "policyVersion": "1.1",
28 | "policySections": [
29 | {
30 | "sectionName": "",
31 | "policyGroups": [
32 | {
33 | "fieldName": "Image Component",
34 | "booleanOperator": "OR",
35 | "negate": false,
36 | "values": [
37 | {
38 | "value": "polkit="
39 | },
40 | {
41 | "value": "policykit-1="
42 | }
43 | ]
44 | }
45 | ]
46 | }
47 | ],
48 | "mitreAttackVectors": [],
49 | "criteriaLocked": false,
50 | "mitreVectorsLocked": false,
51 | "isDefault": false
52 | }
53 | ]
54 | }
--------------------------------------------------------------------------------
/terraform/azure-sentinel/README.md:
--------------------------------------------------------------------------------
1 | # Azure Log Analytics - Sentinel Terraform
2 |
3 | This terraform script will provide all resources to setup an integration with Sentinel and Log Analytics Workspace.
4 |
5 | This terraform script will provision following resources:
6 |
7 | - Resource group
8 | - Log Analytics Workspace
9 | - Data Collection Endpoint
10 | - Data Collection Rule
11 |
12 | This script can be used to provision a custom environment and is used for CI testing.
13 |
14 | For more information visit the documentation in the [stackrox repo's Sentinel notifier](https://github.com/stackrox/stackrox/tree/master/central/notifiers/microsoftsentinel).
15 |
16 | ## Quick start
17 |
18 | Requirements:
19 |
20 | - Install azcli
21 | - Authenticating via a [Service Principal](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret)
22 | - Access to the Microsoft Azure StackRox tenant
23 | - Access to bitwarden
24 |
25 | ```
26 | # Login into Azure, select the subscription.
27 | $ az login
28 |
29 | $ export ARM_SUBSCRIPTION_ID=""
30 | $ export ARM_CLIENT_SECRET=""
31 | $ export ARM_TENANT_ID=""
32 | $ export ARM_CLIENT_ID=""
33 |
34 | $ terraform init
35 | $ terraform fmt
36 | $ terraform validate
37 | $ terraform apply
38 | ```
39 |
40 | For later reference example Data Collection Rule configuration: https://github.com/hashicorp/terraform-provider-azurerm/blob/main/examples/azure-monitoring/data-collection-rule/main.tf
41 |
42 | ### Create a service principal
43 |
44 | In case you need a new service principal you can run the command below. Please only use this if you are
45 | sure you need new credentials. Make sure to save them in bitwarden.
46 |
47 | ```
48 | # Create a service principal for authentication
49 | $ az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/$ARM_SUBSCRIPTION_ID"
50 |
51 | {
52 | "appId": "",
53 | "displayName": "azure-cli-2024-10-07-08-49-10",
54 | "password": "",
55 | "tenant": ""
56 | }
57 | ```
58 |
--------------------------------------------------------------------------------
/terraform/azure-sentinel/main.tf:
--------------------------------------------------------------------------------
1 | resource "azurerm_resource_group" "rg" {
2 | name = "${var.prefix}-resources"
3 | location = var.region
4 | }
5 |
6 | resource "azurerm_monitor_data_collection_endpoint" "endpoint" {
7 | name = "${var.prefix}-data-collection-endpoint"
8 | resource_group_name = azurerm_resource_group.rg.name
9 | location = azurerm_resource_group.rg.location
10 | public_network_access_enabled = true
11 |
12 | lifecycle {
13 | create_before_destroy = true
14 | }
15 | }
16 |
17 | resource "azurerm_log_analytics_workspace" "logworkspace" {
18 | name = "${var.prefix}-log-analytics-workspace"
19 | location = azurerm_resource_group.rg.location
20 | resource_group_name = azurerm_resource_group.rg.name
21 | sku = "PerGB2018"
22 | retention_in_days = 30
23 | }
24 |
25 | # We are using the azapi provider to create custom tables because it is unsupported in the Azure provider.
26 | # This resource links to the data_flow.output_stream field in the `azurerm_monitor_data_collection_rule` resource.
27 | resource "azapi_resource" "data_collection_logs_table" {
28 | name = "stackrox_alerts_CL"
29 | parent_id = azurerm_log_analytics_workspace.logworkspace.id
30 | type = "Microsoft.OperationalInsights/workspaces/tables@2022-10-01"
31 | body = jsonencode(
32 | {
33 | "properties" : {
34 | "schema" : {
35 | "name" : "stackrox_alerts_CL",
36 | "columns" : [
37 | {
38 | "name" : "TimeGenerated",
39 | "type" : "datetime",
40 | "description" : "The time at which the data was generated"
41 | },
42 | {
43 | "name" : "msg",
44 | "type" : "dynamic",
45 | "description" : "StackRox alert message sent by a notifer"
46 | }
47 | ]
48 | },
49 | "retentionInDays" : 30,
50 | "totalRetentionInDays" : 30
51 | }
52 | }
53 | )
54 | }
55 |
56 | # Data Collection Rule
57 | resource "azurerm_monitor_data_collection_rule" "rule" {
58 | name = "${var.prefix}-data-collection-rule"
59 | resource_group_name = azurerm_resource_group.rg.name
60 | location = azurerm_resource_group.rg.location
61 | data_collection_endpoint_id = azurerm_monitor_data_collection_endpoint.endpoint.id
62 | description = "StackRox data collection rule to forward StackRox alerts to the Log Analytics Workspace."
63 |
64 | destinations {
65 | log_analytics {
66 | workspace_resource_id = azurerm_log_analytics_workspace.logworkspace.id
67 | name = "destination-logs"
68 | }
69 | }
70 |
71 | data_flow {
72 | streams = ["Custom-stackrox_alerts_CL"]
73 | destinations = ["destination-logs"]
74 |
75 | # From `data_collection_logs_table.name`. The prefix is prepended by Azure automatically.
76 | output_stream = "Custom-stackrox_alerts_CL"
77 | }
78 |
79 | stream_declaration {
80 | stream_name = "Custom-stackrox_alerts_CL"
81 | column {
82 | name = "msg"
83 | type = "dynamic"
84 | }
85 | column {
86 | name = "TimeGenerated"
87 | type = "datetime"
88 | }
89 | }
90 |
91 | depends_on = [
92 | azurerm_log_analytics_workspace.logworkspace,
93 | azapi_resource.data_collection_logs_table
94 | ]
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/terraform/azure-sentinel/provider.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | azurerm = {
4 | source = "hashicorp/azurerm"
5 | version = "~> 4.4.0"
6 | }
7 | azapi = {
8 | source = "Azure/azapi"
9 | version = "~> 1.8.0"
10 | }
11 | }
12 |
13 | required_version = ">= 1.1.0"
14 | }
15 |
16 | provider "azurerm" {
17 | features {}
18 | }
19 |
--------------------------------------------------------------------------------
/terraform/azure-sentinel/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | type = string
3 | default = "westus2"
4 | description = "The Azure region where the resources should be deployed to."
5 | }
6 |
7 | variable "prefix" {
8 | type = string
9 | default = "stackrox-sentinel"
10 | }
11 |
--------------------------------------------------------------------------------
/util-scripts/acs-correlation-example/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.access.redhat.com/ubi9:9.1.0-1782
2 |
3 | # #ENV Variables
4 | # ENV APP_MODULE testapp:app
5 | # ENV APP_CONFIG gunicorn.conf.py
6 |
7 | #Change User
8 | USER 0
9 |
10 | # Install the required software
11 | RUN dnf install -y wget yum-utils make gcc openssl-devel bzip2-devel libffi-devel zlib-devel && \
12 | wget https://www.python.org/ftp/python/3.10.8/Python-3.10.8.tgz && \
13 | tar xzf Python-3.10.8.tgz && \
14 | cd Python-3.10.8 && \
15 | ./configure --with-system-ffi --with-computed-gotos --enable-loadable-sqlite-extensions && \
16 | make altinstall && \
17 | cd .. && \
18 | rm Python-3.10.8.tgz
19 |
20 | # # Install pip
21 | # RUN curl -O https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py && python3 get-pip.py
22 |
23 | #Make Application Directory
24 | RUN mkdir ./app && cd ./app && echo python -V
25 |
26 | # Copy Files into containers
27 | COPY ./ ./app
28 |
29 | #WORKDIR
30 | WORKDIR ./app
31 |
32 | #Install App Dependecies
33 | RUN pip3.10 install -r requirements.txt && pip3.10 install --upgrade pip
34 |
35 | #Expose Ports
36 | EXPOSE 8080/tcp
37 |
38 | #Change Permissions to allow not root-user work
39 | RUN chmod -R g+rw ./
40 |
41 | #Change User
42 | USER 1001
43 |
44 | #ENTRY
45 | ENTRYPOINT python3.10 app.py
46 |
--------------------------------------------------------------------------------
/util-scripts/acs-correlation-example/README.md:
--------------------------------------------------------------------------------
1 | # Prototype application to parse multiple ACS endpoints collect metadata via the API, correlate data and parse out JSON files.
2 | - Will parse out a hierarchical Cluster->Namespace->Deployment->Alerts Relationship
3 | - Can be extended to parse out other relationships
4 |
5 | # Configuration
6 | - Configuration settings are mostly obtained from enviromnent variables. Configuration settings are provided and explained in [config file](./config.py)
7 |
8 | - The list of endpoints for the app to poll can be set via ENDPOINT_LIST_JSON_PATH environment variable. The environment variable should point to a json file with API details. A sample file is provided in [endpoint_list.json](./endpoint_list.json).While environment details are provided via the previously mentioned variable the token used for connection is obtained via enviroment variable. And the token environment variable must be set in the endpoint json file and defined by field "endpoint_token_env_variable_name".
9 |
10 | - Generate's sample output files in output folder, but can be customized for other use cases.
11 | - cluster_namespace_deployment_alert.json: JSON file with hierarchical Cluster->Namespace->Deployment->Alerts relationship.
12 | - endpoint_policy_alert_count.json: JSON file with ACS Endpoint -> Policy -> AlertCount Relationship
13 |
14 | # Run with Podman
15 | - Build Image
16 | ```bash
17 | podman build -t quick_acs_app .
18 | ```
19 |
20 | - Run Container
21 | ```bash
22 | podman run --env $MAIN_ACS_TOKEN --env OUTPUT_FOLDER=/output -v /tmp/output:/output:Z localhost/quick_acs_app
23 | ```
--------------------------------------------------------------------------------
/util-scripts/acs-correlation-example/config.py:
--------------------------------------------------------------------------------
1 | from pydantic_settings import BaseSettings
2 | import os
3 | from dotenv import load_dotenv # pylint: disable=import-error
4 |
5 | basedir = os.path.abspath(os.path.dirname(__file__))
6 | load_dotenv(os.path.join(basedir, '.env'))
7 |
8 | class Settings(BaseSettings):
9 | """Application Settings """
10 |
11 | #If multiple versions of this Applications Hostname are running, this will help identify them
12 | instance_hostname:str = os.environ.get('HOSTNAME') or 'demo_app'
13 |
14 | #File Path where we can look for the list of ACS API Endpoints to work with
15 | endpoint_list_json_path:str = os.environ.get('ENDPOINT_LIST_JSON_PATH') or 'endpoint_list.json'
16 |
17 | #Health Check Retry Count
18 | health_check_retry_count:int = os.environ.get('HEALTH_CHECK_RETRY_COUNT') or 3
19 |
20 | #Health Check Retry Delay in Seconds
21 | health_check_retry_delay:int = os.environ.get('HEALTH_CHECK_RETRY_DELAY') or 10
22 |
23 | #Poll Disabled Policy Information
24 | poll_disabled_policy_info:bool = os.environ.get('POLL_DISABLED_POLICY_INFO') or False
25 |
26 | #Output folder for the Policy output
27 | output_folder:str = os.environ.get('OUTPUT_FOLDER') or 'output'
28 |
29 | settings = Settings()
30 |
31 |
32 |
--------------------------------------------------------------------------------
/util-scripts/acs-correlation-example/endpoint_list.json:
--------------------------------------------------------------------------------
1 | {
2 | "endpoints": [
3 | {
4 | "endpoint_name": "ACS_Demo_Environment",
5 | "endpoint_url": "https://central-rhacs-operator.apps.cluster11.sandbox2585.opentlc.com",
6 | "endpoint_url_description": "ACS API endpoint for the application to make requess to",
7 | "endpoint_token_env_variable_name": "MAIN_ACS_TOKEN",
8 | "verify_endpoint_ssl" : "False",
9 | "endpoint_token_env_variable_name_description": "Environment Variable to retrieve the Token for this cluster"
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/util-scripts/acs-correlation-example/logging.conf:
--------------------------------------------------------------------------------
1 |
2 | [loggers]
3 | keys=root
4 |
5 | [handlers]
6 | keys=consoleHandler,detailedConsoleHandler
7 |
8 | [formatters]
9 | keys=normalFormatter,detailedFormatter
10 |
11 | [logger_root]
12 | level=DEBUG
13 | handlers=consoleHandler
14 |
15 | [handler_consoleHandler]
16 | class=StreamHandler
17 | level=INFO
18 | formatter=normalFormatter
19 | args=(sys.stdout,)
20 |
21 | [handler_detailedConsoleHandler]
22 | class=StreamHandler
23 | level=DEBUG
24 | formatter=detailedFormatter
25 | args=(sys.stdout,)
26 |
27 | [formatter_normalFormatter]
28 | format=%(asctime)s loglevel=%(levelname)-6s logger=%(name)s %(funcName)s() L%(lineno)-4d %(message)s
29 |
30 | [formatter_detailedFormatter]
31 | format=%(asctime)s loglevel=%(levelname)-6s logger=%(name)s %(funcName)s() L%(lineno)-4d %(message)s call_trace=%(pathname)s L%(lineno)-4d
--------------------------------------------------------------------------------
/util-scripts/acs-correlation-example/requirements.txt:
--------------------------------------------------------------------------------
1 | aiofiles==23.2.1
2 | annotated-types==0.7.0
3 | anyio==4.4.0
4 | certifi==2024.7.4
5 | click==8.1.7
6 | dnspython==2.6.1
7 | email_validator==2.1.1
8 | exceptiongroup==1.2.1
9 | fastapi==0.111.0
10 | fastapi-cli==0.0.4
11 | h11==0.14.0
12 | httpcore==1.0.5
13 | httptools==0.6.1
14 | httpx==0.27.0
15 | idna==3.7
16 | Jinja2==3.1.4
17 | markdown-it-py==3.0.0
18 | MarkupSafe==2.1.5
19 | mdurl==0.1.2
20 | orjson==3.10.4
21 | pydantic==2.7.4
22 | pydantic-settings==2.3.3
23 | pydantic_core==2.18.4
24 | Pygments==2.18.0
25 | python-dotenv==1.0.1
26 | python-multipart==0.0.9
27 | PyYAML==6.0.1
28 | rich==13.7.1
29 | shellingham==1.5.4
30 | sniffio==1.3.1
31 | starlette==0.37.2
32 | typer==0.12.3
33 | typing_extensions==4.12.2
34 | ujson==5.10.0
35 | uuid==1.30
36 | uvicorn==0.30.1
37 | uvloop==0.19.0
38 | watchfiles==0.22.0
39 | websockets==12.0
40 |
--------------------------------------------------------------------------------
/util-scripts/compliance-scans-classifications/stackrox_classifications.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #here is how to use the API to push a logon banner as well as header and footers for classification.
4 | # ac - 8/18/2020
5 |
6 | central_server=stackrox.dockr.life:443
7 |
8 | #########
9 |
10 | function get_password (){
11 | #read the admin password
12 | echo -n " - StackRox Admin Password for $serverUrl: "; read -s password; echo
13 | }
14 |
15 | #gov logon message
16 | export gov_message=$(cat < /dev/null 2>&1
26 | ;;
27 |
28 | S )
29 | #secret
30 | get_password
31 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":true,"text":"'"$gov_message"'"},"header":{"enabled":true,"text":"SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#d9534f"},"footer":{"enabled":true,"text":"SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#d9534f"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1
32 | ;;
33 |
34 | TS )
35 | #top secret
36 | get_password
37 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":true,"text":"'"$gov_message"'"},"header":{"enabled":true,"text":"TOP SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"},"footer":{"enabled":true,"text":"TOP SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1
38 | ;;
39 |
40 | clear )
41 | #clear
42 | get_password
43 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":false,"text":"'"$gov_message"'"},"header":{"enabled":false,"text":"","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"},"footer":{"enabled":false,"text":"","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1
44 | ;;
45 |
46 | *) echo "Usage: $0 {clear | TS | S | U}"; exit 1
47 |
48 | esac
49 |
--------------------------------------------------------------------------------
/util-scripts/compliance-scans-classifications/stackrox_compliance_scan.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # clemenko@stackrox.com
3 |
4 | standardId="NIST_800_190"
5 | #supported standards CIS_Kubernetes_v1_5 HIPAA_164 NIST_800_190 NIST_SP_800_53_Rev_4 PCI_DSS_3_2 CIS_Docker_v1_2_0
6 | ###### no more edits
7 |
8 | RED=$(tput setaf 1)
9 | GREEN=$(tput setaf 2)
10 | NORMAL=$(tput sgr0)
11 |
12 | function setup () { # setup role and token
13 |
14 | echo -e "\n Creating the API token. Admin password required. "
15 | #read the admin password
16 | echo -n " - StackRox Admin Password for $serverUrl: "; read -s password; echo
17 |
18 | # check to see if the role is there.
19 | if [ $(curl -sk -u admin:$password https://$serverUrl/v1/roles | jq '.roles[] | select(.name=="Compliance")' | wc -l) = 0 ]; then
20 | # create the role
21 | curl -sk -u admin:$password -X POST 'https://'$serverUrl'/v1/roles/Compliance' \
22 | -H 'accept: application/json, text/plain, */*' \
23 | -d '{"name":"Compliance","globalAccess":"NO_ACCESS","resourceToAccess":{"Cluster": "READ_ACCESS","Compliance":"READ_WRITE_ACCESS","ComplianceRunSchedule":"READ_WRITE_ACCESS","ComplianceRuns":"READ_WRITE_ACCESS"}}'
24 | fi
25 |
26 | # create token with new role
27 | curl -sk -X POST -u admin:$password https://$serverUrl/v1/apitokens/generate -d '{"name":"compliance","role":null,"roles":["Compliance"]}'| jq -r .token > stackrox_api.token
28 |
29 | echo -e "\n----------------------------------------------------------------------------------"
30 | }
31 |
32 | echo -e "\n StackRox Compliance Automation Script"
33 | echo " - Inputs: ./stackrox_compliance_scan.sh "
34 | echo " - Outputs: ___Results_$(date +"%m-%d-%y").json"
35 | echo -e "----------------------------------------------------------------------------------\n"
36 |
37 | serverUrl=$1
38 | if [ -z $serverUrl ]; then echo "$RED [warn]$NORMAL Please add the server name to the command."; echo ""; exit; fi
39 |
40 | # if stackrox_api.token exists
41 | if [ ! -f stackrox_api.token ]; then setup; fi
42 |
43 | # get api
44 | export token=$(cat stackrox_api.token)
45 |
46 | echo -n "Running $standardId scan on $serverUrl "
47 |
48 | #get clusterId
49 | clusterId=$(curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/clusters | jq -r .clusters[0].id)
50 |
51 | clusterName=$(curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/clusters/$clusterId | jq -r .cluster.name)
52 |
53 | runId=$(curl -sk -X POST -H "Authorization: Bearer $token" https://$serverUrl/v1/compliancemanagement/runs -d '{"selection": { "clusterId": "'"$clusterId"'", "standardId": "'"$standardId"'" }}' | jq -r .startedRuns[0].id)
54 |
55 | until [ "$(curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/complianceManagement/runs | jq -r '.complianceRuns[]|select(.id=="'"$runId"'") | .state' )" == "FINISHED" ]; do echo -n "."; sleep 1; done
56 |
57 | curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/compliance/runresults?clusterId="$clusterId"'&standardId='$standardId'&runId='$runId'' | jq . > "$serverUrl"_"$clusterName"_"$standardId"_Results_$(date +"%m-%d-%y").json
58 |
59 | echo -e "$GREEN" "[ok]" "$NORMAL\n"
60 |
--------------------------------------------------------------------------------
/util-scripts/component-details-to-csv/README.md:
--------------------------------------------------------------------------------
1 | This script exports component details to CSV, including: cluster, namespace, deployment, image, component and component version.
2 |
3 | Required Environment Vars:
4 |
5 | ROX_ENDPOINT - Host for StackRox central (central.example.com)
6 | ROX_API_TOKEN - Token data from StackRox API token
7 | Required Argument:
8 |
9 | $1 = path/to/output_file.csv
10 | Usage "component_details_csv.sh