Skip to content

Commit

Permalink
implement workload identity for GKE (#976)
Browse files Browse the repository at this point in the history
* implement workload identity for GKE

* add repository mirrors
  • Loading branch information
vitorvezani authored Oct 28, 2024
1 parent 77df9f7 commit dca48af
Show file tree
Hide file tree
Showing 19 changed files with 351 additions and 165 deletions.
11 changes: 4 additions & 7 deletions plugins/ci/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 5.7.8
- Use `RemoveTokensAndPassword` function from trivy
- Add trivy OCI repositories fallback

## 5.7.7
- bumped trivy to v0.56.2

Expand All @@ -22,31 +26,24 @@
- fixed docker vulnerability

## 5.7.0

- Add support for OPA custom libs

## 5.6.2

- fixed docker vulnerability

## 5.6.1

- add support for go workspace

## 5.6.0

- Add support for scan-workloads labels

## 5.5.9

- Bumped trivy version

## 5.5.8

- Fixed CI vulnerability

## 5.5.7

- Bump alpine to 3.20

## 5.5.6
Expand Down
2 changes: 1 addition & 1 deletion plugins/ci/pkg/ci/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"

"github.com/fairwindsops/insights-plugins/plugins/ci/pkg/models"
"github.com/fairwindsops/insights-plugins/plugins/ci/pkg/util"
"github.com/fairwindsops/insights-plugins/plugins/trivy/pkg/util"
"github.com/sirupsen/logrus"
)

Expand Down
10 changes: 8 additions & 2 deletions plugins/ci/pkg/ci/trivy.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,13 @@ func scanImagesWithTrivy(images []trivymodels.Image, configurationObject models.
return nil, "", fmt.Errorf("unable to get trivy version: %v", err)
}
trivyVersion = strings.Split(strings.Split(trivyVersion, "\n")[0], " ")[1]
output, err := commands.ExecWithMessage(exec.Command("trivy", "image", "--download-db-only"), "downloading trivy database")

args := []string{
"image", "--download-db-only",
"--db-repository", "ghcr.io/aquasecurity/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2,docker.io/aquasec/trivy-db:2",
"--java-db-repository", "ghcr.io/aquasecurity/trivy-java-db:1,public.ecr.aws/aquasecurity/trivy-java-db:1,docker.io/aquasec/trivy-java-db:1",
}
output, err := commands.ExecWithMessage(exec.Command("trivy", args...), "downloading trivy database")
if err != nil {
return nil, "", fmt.Errorf("unable to download trivy database, %v: %s", err, output)
}
Expand Down Expand Up @@ -452,7 +458,7 @@ func ScanImageFile(imagePath, imageID, tempDir, extraFlags string) (*trivymodels
if extraFlags != "" {
cmd = exec.Command("trivy", "-d", "image", "--skip-update", extraFlags, "-f", "json", "-o", reportFile, "--input", imagePath)
}
err := util.RunCommand(cmd, "scanning "+imageID)
_, err := util.RunCommand(cmd, "scanning "+imageID)
if err != nil {
logrus.Errorf("Error scanning %s at %s: %v", imageID, imagePath, err)
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion plugins/ci/pkg/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"os/exec"

"github.com/fairwindsops/insights-plugins/plugins/ci/pkg/util"
"github.com/fairwindsops/insights-plugins/plugins/trivy/pkg/util"
"github.com/sirupsen/logrus"
)

Expand Down
28 changes: 0 additions & 28 deletions plugins/ci/pkg/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,34 +49,6 @@ func ExactlyOneOf(inputs ...bool) bool {
return foundAtLeastOne
}

// RemoveTokensAndPassword sanitizes output to remove token
func RemoveTokensAndPassword(s string) string {
// based on x-access-token
index := strings.Index(s, "x-access-token")
index2 := strings.Index(s, "@github.com")
if index > 0 && index2 > 0 {
return strings.ReplaceAll(s, s[index+15:index2], "<TOKEN>")
}

// based on --src-creds
index = strings.Index(s, "--src-creds")
if index > 0 {
f := index + 12 // start of credentials
l := strings.Index(s, " docker")
return strings.ReplaceAll(s, s[f:l], "<CREDENTIALS>")
}

// based on --src-registry-token
index = strings.Index(s, "--src-registry-token")
if index > 0 {
f := index + 21 // start of credentials
l := strings.Index(s, " docker")
return strings.ReplaceAll(s, s[f:l], "<TOKEN>")
}

return s
}

func PrettyPrint(i any) string {
s, _ := json.Marshal(i)
return string(s)
Expand Down
6 changes: 0 additions & 6 deletions plugins/ci/pkg/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ import (
"github.com/stretchr/testify/assert"
)

func TestRemoveTokensAndPassword(t *testing.T) {
assert.Equal(t, "https://x-access-token:<TOKEN>@github.com/FairwindsOps/charts", RemoveTokensAndPassword("https://x-access-token:[email protected]/FairwindsOps/charts"))
assert.Equal(t, "/usr/bin/skopeo copy --src-creds <CREDENTIALS> docker://alpine:3.13.0 docker-archive:/app/repository/tmp/_insightsTempImages/alpine3130", RemoveTokensAndPassword("/usr/bin/skopeo copy --src-creds username:password docker://alpine:3.13.0 docker-archive:/app/repository/tmp/_insightsTempImages/alpine3130"))
assert.Equal(t, "/usr/bin/skopeo copy --src-registry-token <TOKEN> docker://alpine:3.13.0 docker-archive:/app/repository/tmp/_insightsTempImages/alpine3130", RemoveTokensAndPassword("/usr/bin/skopeo copy --src-registry-token my-secret-token docker://alpine:3.13.0 docker-archive:/app/repository/tmp/_insightsTempImages/alpine3130"))
}

func TestExtractMetadata(t *testing.T) {
type want struct {
apiVersion, kind, name, namespace string
Expand Down
2 changes: 1 addition & 1 deletion plugins/ci/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.7.7
5.7.8
6 changes: 5 additions & 1 deletion plugins/trivy/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Changelog

## 0.31.0
* Add new env. variable support `SERVICE_ACCOUNT_ANNOTATIONS`
* Add private GCP containers / registry support for skopeo copy

## 0.30.3
* bump trivy for fixing vulnerabilities

## 0.30.2
* fixing vulberabilities
* fixing vulnerabilities

## 0.30.1
* upgraded goreleaser to v2
Expand Down
23 changes: 22 additions & 1 deletion plugins/trivy/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,33 @@ RUN if [ "${TARGETARCH}" = "amd64" ] ; then trivyArch="64bit"; else trivyArch="$
FROM alpine:3.20
WORKDIR /trivy
RUN apk -U upgrade

# for gcloud
RUN apk --no-cache add bash curl python3 libc6-compat ca-certificates

ENV CLOUD_SDK_VERSION=497.0.0

RUN curl -LO https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz && \
tar -xvf google-cloud-cli-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz && \
rm google-cloud-cli-${CLOUD_SDK_VERSION}-linux-x86_64.tar.gz && \
google-cloud-sdk/install.sh --quiet --path-update=false && \
rm -rf /trivy/google-cloud-sdk/platform/gsutil/third_party && \
rm -r /trivy/google-cloud-sdk/bin/gcloud-crc32c && \
rm -f /trivy/google-cloud-sdk/lib/third_party/google/auth/crypt/__pycache__/_python_rsa.cpython-312.pyc && \
rm -f /trivy/google-cloud-sdk/lib/third_party/oauth2client/__pycache__/_pure_python_crypt.cpython-312.pyc

ENV PATH=$PATH:/trivy/google-cloud-sdk/bin

COPY scan ./scan
COPY --from=downloader /usr/local/bin/kubectl /usr/local/bin/kubectl
COPY --from=downloader /usr/local/bin/trivy /usr/local/bin/trivy

RUN TRIVY_CACHE_DIR=/var/tmp trivy image --download-db-only
RUN TRIVY_CACHE_DIR=/var/tmp trivy image \
--download-db-only \
--db-repository "ghcr.io/aquasecurity/trivy-db:2","public.ecr.aws/aquasecurity/trivy-db:2","docker.io/aquasec/trivy-db:2" \
--java-db-repository "ghcr.io/aquasecurity/trivy-java-db:1","public.ecr.aws/aquasecurity/trivy-java-db:1","docker.io/aquasec/trivy-java-db:1"

ENV CLOUDSDK_CONFIG=/tmp/gcloud
ENV HOME=/
RUN mkdir $HOME/.docker

Expand Down
115 changes: 42 additions & 73 deletions plugins/trivy/cmd/trivy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@ import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"

"github.com/fairwindsops/insights-plugins/plugins/trivy/pkg/config"
"github.com/fairwindsops/insights-plugins/plugins/trivy/pkg/image"
"github.com/fairwindsops/insights-plugins/plugins/trivy/pkg/util"
"github.com/sirupsen/logrus"
)

var maxConcurrentScans = 5
var numberToScan = 10
var extraFlags string

const outputFile = image.TempDir + "/final-report.json"

/*
Expand All @@ -29,7 +24,29 @@ const outputFile = image.TempDir + "/final-report.json"
func main() {
ctx := context.TODO()
setLogLevel(os.Getenv("LOGRUS_LEVEL"))
setEnv()
cfg, err := config.LoadFromEnvironment()
if err != nil {
logrus.Fatalf("could not set environment variables: %v", err)
}

logrus.Debugf("config is %#v", *cfg)

err = util.CheckEnvironmentVariables()
if err != nil {
logrus.Fatal("error checking environment variables: ", err)
}

if !cfg.Offline {
args := []string{
"image", "--download-db-only",
"--db-repository", "ghcr.io/aquasecurity/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2,docker.io/aquasec/trivy-db:2",
"--java-db-repository", "ghcr.io/aquasecurity/trivy-java-db:1,public.ecr.aws/aquasecurity/trivy-java-db:1,docker.io/aquasec/trivy-java-db:1",
}
_, err := util.RunCommand(exec.Command("trivy", args...), "downloading trivy database")
if err != nil {
logrus.Fatal(err)
}
}

host := os.Getenv("FAIRWINDS_INSIGHTS_HOST")
org := os.Getenv("FAIRWINDS_ORG")
Expand All @@ -46,10 +63,8 @@ func main() {
logrus.Debugf("%v - %v", i.Name, i.ID)
}

namespaceBlocklist, namespaceAllowlist := getNamespaceBlocklistAllowlistFromEnv()
logrus.Infof("%d namespaces allowed, %d namespaces blocked", len(namespaceAllowlist), len(namespaceBlocklist))

inClusterImages, err := image.GetImages(ctx, namespaceBlocklist, namespaceAllowlist)
logrus.Infof("%d namespaces allowed, %d namespaces blocked", len(cfg.NamespaceAllowlist), len(cfg.NamespaceBlocklist))
inClusterImages, err := image.GetImages(ctx, cfg.NamespaceBlocklist, cfg.NamespaceAllowlist)
if err != nil {
logrus.Fatal(err)
}
Expand All @@ -58,10 +73,10 @@ func main() {
logrus.Debugf("%v - %v", i.Name, i.ID)
}

imagesToScan := image.GetUnscannedImagesToScan(inClusterImages, lastReport.Images, numberToScan)
imagesToScan := image.GetUnscannedImagesToScan(inClusterImages, lastReport.Images, cfg.NumberToScan)
unscannedCount := len(imagesToScan)
logrus.Infof("Found %d images that have never been scanned", unscannedCount)
imagesToScan = image.GetImagesToReScan(inClusterImages, *lastReport, imagesToScan, numberToScan)
imagesToScan = image.GetImagesToReScan(inClusterImages, *lastReport, imagesToScan, cfg.NumberToScan)
logrus.Infof("Will re-scan %d additional images", len(imagesToScan)-unscannedCount)
for _, i := range imagesToScan {
logrus.Debugf("%v - %v", i.Name, i.ID)
Expand All @@ -79,17 +94,28 @@ func main() {
lastReport.Images = image.GetMatchingImages(lastReport.Images, inClusterImages, true)
logrus.Infof("%d images after removing recommendations that don't match", len(lastReport.Images))

registryOAuth2AccessTokenMap := map[string]string{}
if cfg.HasGKESAAnnotation {
// it seems that AWS IRSA is support but not GKE SA, so we need to get the token manually and inject into skopeo
oauth2AccessToken, err := util.RunCommand(exec.Command("gcloud", "auth", "print-access-token"), "getting gcloud access token")
if err != nil {
logrus.Fatalf("could not get gcloud access token: %v", err)
}
registryOAuth2AccessTokenMap["gcr.io"] = oauth2AccessToken
registryOAuth2AccessTokenMap["docker.pkg.dev"] = oauth2AccessToken
}

logrus.Infof("Starting image scans")
allReports := image.ScanImages(image.ScanImage, imagesToScan, maxConcurrentScans, extraFlags)
allReports := image.ScanImages(image.ScanImage, imagesToScan, cfg.MaxConcurrentScans, cfg.ExtraFlags, registryOAuth2AccessTokenMap)

if noRecommendations == "" {
logrus.Infof("Scanning recommendations")
recommendationsToScan := image.GetNewestVersionsToScan(ctx, allReports, imagesToScan)
recommendationsToScan := image.GetNewestVersionsToScan(ctx, allReports, imagesToScan, registryOAuth2AccessTokenMap)
// Remove any recommendations from the report that we're going to re-scan now
lastReport.Images = image.GetUnmatchingImages(lastReport.Images, recommendationsToScan, true)
logrus.Infof("%d images after removing recommendations that will be scanned", len(lastReport.Images))
logrus.Infof("Scanning %d recommended images", len(recommendationsToScan))
recommendationReport := image.ScanImages(image.ScanImage, recommendationsToScan, maxConcurrentScans, extraFlags)
recommendationReport := image.ScanImages(image.ScanImage, recommendationsToScan, cfg.MaxConcurrentScans, cfg.ExtraFlags, registryOAuth2AccessTokenMap)
logrus.Infof("Done scanning recommendations")
allReports = append(allReports, recommendationReport...)
}
Expand All @@ -107,20 +133,6 @@ func main() {
logrus.Info("Finished writing file ", outputFile)
}

func getNamespaceBlocklistAllowlistFromEnv() ([]string, []string) {
var namespaceBlocklist, namespaceAllowlist []string
if os.Getenv("NAMESPACE_BLACKLIST") != "" {
namespaceBlocklist = strings.Split(os.Getenv("NAMESPACE_BLACKLIST"), ",")
}
if os.Getenv("NAMESPACE_BLOCKLIST") != "" {
namespaceBlocklist = strings.Split(os.Getenv("NAMESPACE_BLOCKLIST"), ",")
}
if os.Getenv("NAMESPACE_ALLOWLIST") != "" {
namespaceAllowlist = strings.Split(os.Getenv("NAMESPACE_ALLOWLIST"), ",")
}
return namespaceBlocklist, namespaceAllowlist
}

func setLogLevel(logLevel string) {
if logLevel != "" {
lvl, err := logrus.ParseLevel(logLevel)
Expand All @@ -132,46 +144,3 @@ func setLogLevel(logLevel string) {
logrus.SetLevel(logrus.InfoLevel)
}
}

func setEnv() {
concurrencyStr := os.Getenv("MAX_CONCURRENT_SCANS")
if concurrencyStr != "" {
var err error
maxConcurrentScans, err = strconv.Atoi(concurrencyStr)
if err != nil {
panic(err)
}
}

numberToScanStr := os.Getenv("MAX_SCANS")
if numberToScanStr != "" {
var err error
numberToScan, err = strconv.Atoi(numberToScanStr)
if err != nil {
panic(err)
}
}

ignoreUnfixedStr := os.Getenv("IGNORE_UNFIXED")
if ignoreUnfixedStr != "" {
ignoreUnfixedBool, err := strconv.ParseBool(ignoreUnfixedStr)
if err != nil {
panic(err)
}
if ignoreUnfixedBool {
extraFlags += "--ignore-unfixed"
}
}

if os.Getenv("OFFLINE") == "" {
err := util.RunCommand(exec.Command("trivy", "image", "--download-db-only"), "downloading trivy database")
if err != nil {
panic(err)
}
}

err := util.CheckEnvironmentVariables()
if err != nil {
panic(err)
}
}
Loading

0 comments on commit dca48af

Please sign in to comment.