Skip to content

Commit

Permalink
fix workload scan image secrets
Browse files Browse the repository at this point in the history
Signed-off-by: Amir Malka <amirm@armosec.io>
  • Loading branch information
amirmalka committed Jan 14, 2024
1 parent b76f1b0 commit f14d7b5
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 11 deletions.
97 changes: 97 additions & 0 deletions .github/workflows/hotfix-pr-merged.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: build
on:
push:
branches:
- 'v0.2.139-hotfix'
paths-ignore:
- '**.md' ### Ignore running when README.MD changed.
- '.github/workflows/*' ### Ignore running when files under path: .github/workflows/* changed.

jobs:
docker-build:
runs-on: ubuntu-latest
permissions:
id-token: write
packages: write
contents: read
pull-requests: read

steps:

- uses: actions/checkout@v3
name: Checkout
with:
fetch-depth: 0
# submodules: recursive

- uses: actions/setup-go@v4
name: Installing go
with:
go-version: 1.21

- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Set prerelease image tag
id: image-prerelease-tag
run: echo "IMAGE_TAG_PRERELEASE=v0.1.70-hotfix" >> $GITHUB_OUTPUT

- name: Run unit test
id: unit-test
run: go test -v ./...

- name: Login to Quay
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
password: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}

- name: Build and push
uses: docker/build-push-action@v3
with:
context: .
file: build/Dockerfile
tags: quay.io/kubescape/kubevuln:v0.2.139-hotfix
build-args: image_version=v0.2.139-hotfix
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
push: true

- name: Install cosign
uses: sigstore/cosign-installer@main
with:
cosign-release: 'v2.2.2'

- name: sign kubescape container image
env:
COSIGN_EXPERIMENTAL: "true"
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY_V1 }}
COSIGN_PRIVATE_KEY_PASSWORD: ${{ secrets.COSIGN_PRIVATE_KEY_V1_PASSWORD }}
COSIGN_PUBLIC_KEY: ${{ secrets.COSIGN_PUBLIC_KEY_V1 }}
run: |
# Sign the image with keyless mode
cosign sign -y quay.io/kubescape/kubevuln:v0.2.139-hotfix
# Sign the image with key for verifier clients without keyless support
# Put the key from environment variable to a file
echo "$COSIGN_PRIVATE_KEY" > cosign.key
printf "$COSIGN_PRIVATE_KEY_PASSWORD" | cosign sign -key cosign.key -y quay.io/kubescape/kubevuln:v0.2.139-hotfix
rm cosign.key
# Verify the image
echo "$COSIGN_PUBLIC_KEY" > cosign.pub
cosign verify -key cosign.pub quay.io/kubescape/kubevuln:v0.2.139-hotfix
- name: Create Release
id: create_release
uses: ncipollo/release-action@v1.11.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: v0.2.139-hotfix
name: Release v0.2.139-hotfix
draft: false
prerelease: false
59 changes: 48 additions & 11 deletions core/services/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
"strings"
"time"

"github.com/akyoto/cache"
"github.com/armosec/armoapi-go/armotypes"
"github.com/docker/docker/api/types/registry"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"github.com/google/uuid"
"github.com/kubescape/go-logger"
Expand Down Expand Up @@ -362,26 +365,60 @@ func generateScanID(workload domain.ScanCommand) string {

func optionsFromWorkload(workload domain.ScanCommand) domain.RegistryOptions {
options := domain.RegistryOptions{}
for _, cred := range workload.Credentialslist {
if cred.Auth != "" {
options.Credentials = append(options.Credentials, domain.RegistryCredentials{Authority: cred.Auth})
}
if cred.RegistryToken != "" {
options.Credentials = append(options.Credentials, domain.RegistryCredentials{Token: cred.RegistryToken})
}
if cred.Username != "" && cred.Password != "" {
options.Credentials = append(options.Credentials, domain.RegistryCredentials{Username: cred.Username, Password: cred.Password})
}
}
options.Credentials = registryCredentialsFromCredentialsList(workload.Credentialslist)

if useHTTP, ok := workload.Args[domain.AttributeUseHTTP]; ok {
options.InsecureUseHTTP = useHTTP.(bool)
}
if skipTLSVerify, ok := workload.Args[domain.AttributeSkipTLSVerify]; ok {
options.InsecureSkipTLSVerify = skipTLSVerify.(bool)
}

logger.L().Debug("created registryOptions from workload",
helpers.String("imageTag", workload.ImageTag),
helpers.String("credentials", credentialsLog(options.Credentials)))
return options
}

// credentialsLog returns a string representation of the credentials without the password and token
func credentialsLog(credentials []domain.RegistryCredentials) string {
var sb strings.Builder
for _, rc := range credentials {
sb.WriteString(fmt.Sprintf("[Authority: %s, Username: %s, Password: *** (%d), Token: *** (%d)]", rc.Authority, rc.Username, len(rc.Password), len(rc.Token)))
}

return sb.String()
}

func registryCredentialsFromCredentialsList(credentials []registry.AuthConfig) []domain.RegistryCredentials {
registryCredentials := make([]domain.RegistryCredentials, len(credentials))
for i, cred := range credentials {
rc := domain.RegistryCredentials{}
if cred.ServerAddress != "" {
rc.Authority = parseAuthorityFromServerAddress(cred.ServerAddress)
}
if cred.RegistryToken != "" {
rc.Token = cred.RegistryToken
}
if cred.Username != "" && cred.Password != "" {
rc.Username = cred.Username
rc.Password = cred.Password
}

registryCredentials[i] = rc
}
return registryCredentials
}

func parseAuthorityFromServerAddress(serverAddress string) string {
parsedURL, err := url.Parse(serverAddress)
if err != nil || parsedURL.Host == "" {
return serverAddress
}

return parsedURL.Host
}

func (s *ScanService) ValidateGenerateSBOM(ctx context.Context, workload domain.ScanCommand) (context.Context, error) {
_, span := otel.Tracer("").Start(ctx, "ScanService.ValidateGenerateSBOM")
defer span.End()
Expand Down
41 changes: 41 additions & 0 deletions core/services/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/kubescape/kubevuln/adapters"
v1 "github.com/kubescape/kubevuln/adapters/v1"
"github.com/kubescape/kubevuln/core/domain"
Expand Down Expand Up @@ -597,3 +598,43 @@ func Test_generateScanID(t *testing.T) {
})
}
}

func Test_registryCredentialsFromCredentialsList(t *testing.T) {
creds := []registry.AuthConfig{
{
ServerAddress: "quay.io",
Auth: "YXJtb3NlYyt0ZXN0cm9ib3QxOmR1bW15UGFzc3dvcmQ=",
Username: "armosec+testrobot1",
Password: "dummyPassword",
},
{
ServerAddress: "https://index.docker.io/v1/",
Username: "test_user",
Password: "dummyPassword",
Email: "test_user@gmail.com",
Auth: "dGVzdF91c2VyOmR1bW15UGFzc3dvcmQ=",
},
{
ServerAddress: "quay.io",
Auth: "YXJtb3NlYyt0ZXN0cm9ib3QyOmR1bW15UGFzc3dvcmQxMTE=",
Username: "armosec+testrobot2",
Password: "dummyPassword111",
},
}
registryCredentials := registryCredentialsFromCredentialsList(creds)
assert.Equal(t, 3, len(registryCredentials))
assert.Equal(t, "quay.io", registryCredentials[0].Authority)
assert.Equal(t, "armosec+testrobot1", registryCredentials[0].Username)
assert.Equal(t, "dummyPassword", registryCredentials[0].Password)
assert.Equal(t, "index.docker.io", registryCredentials[1].Authority)
assert.Equal(t, "test_user", registryCredentials[1].Username)
assert.Equal(t, "dummyPassword", registryCredentials[1].Password)
assert.Equal(t, "quay.io", registryCredentials[2].Authority)
assert.Equal(t, "armosec+testrobot2", registryCredentials[2].Username)
assert.Equal(t, "dummyPassword111", registryCredentials[2].Password)
}

func Test_parseAuthorityFromServerAddress(t *testing.T) {
assert.Equal(t, "index.docker.io", parseAuthorityFromServerAddress("https://index.docker.io/v1/"))
assert.Equal(t, "quay.io", parseAuthorityFromServerAddress("quay.io"))
}

0 comments on commit f14d7b5

Please sign in to comment.