Skip to content

Commit e7a301b

Browse files
authored
feat: Add proxy support and update to inline-scan V2 final version (#7)
* feat: Add proxy support and update to inline-scan V2 final version * Add --registry-skip-tls and --sysdig-skip-tls when verify_ssl is false * fix: restore env after tests, or randomized execution might fail
1 parent 4cac537 commit e7a301b

File tree

5 files changed

+125
-47
lines changed

5 files changed

+125
-47
lines changed

cmd/harbor-scanner-sysdig-secure/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ func getAdapter() scanner.Adapter {
8282
clientset,
8383
viper.GetString("secure_url"),
8484
viper.GetString("namespace_name"),
85-
viper.GetString("secret_name"))
85+
viper.GetString("secret_name"),
86+
viper.GetBool("verify_ssl"))
8687
}
8788

8889
log.Info("Using backend-scanning adapter")

pkg/http/api/v1/handler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
type requestHandler struct {
1818
adapter scanner.Adapter
19-
logger Logger
19+
logger Logger
2020
}
2121

2222
type Logger interface {
@@ -28,7 +28,7 @@ type Logger interface {
2828
func NewAPIHandler(adapter scanner.Adapter, logger Logger) http.Handler {
2929
handler := requestHandler{
3030
adapter: adapter,
31-
logger: logger,
31+
logger: logger,
3232
}
3333

3434
router := mux.NewRouter()

pkg/scanner/inline_adapter.go

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"crypto/md5"
66
"fmt"
7+
"os"
78
"time"
89

910
batchv1 "k8s.io/api/batch/v1"
@@ -22,16 +23,18 @@ type inlineAdapter struct {
2223
secureURL string
2324
namespace string
2425
secret string
26+
verifySSL bool
2527
jobTTL int32
2628
}
2729

28-
func NewInlineAdapter(secureClient secure.Client, k8sClient kubernetes.Interface, secureURL string, namespace string, secret string) Adapter {
30+
func NewInlineAdapter(secureClient secure.Client, k8sClient kubernetes.Interface, secureURL string, namespace string, secret string, verifySSL bool) Adapter {
2931
return &inlineAdapter{
3032
BaseAdapter: BaseAdapter{secureClient: secureClient},
3133
k8sClient: k8sClient,
3234
secureURL: secureURL,
3335
namespace: namespace,
3436
secret: secret,
37+
verifySSL: verifySSL,
3538
jobTTL: int32(24 * time.Hour.Seconds()),
3639
}
3740
}
@@ -64,6 +67,34 @@ func (i *inlineAdapter) buildJob(req harbor.ScanRequest) *batchv1.Job {
6467
user, password := getUserAndPasswordFrom(req.Registry.Authorization)
6568
userPassword := fmt.Sprintf("%s:%s", user, password)
6669

70+
var envVars = []corev1.EnvVar{
71+
{
72+
Name: "SYSDIG_API_TOKEN",
73+
ValueFrom: &corev1.EnvVarSource{
74+
SecretKeyRef: &corev1.SecretKeySelector{
75+
LocalObjectReference: corev1.LocalObjectReference{
76+
Name: i.secret,
77+
},
78+
Key: "sysdig_secure_api_token",
79+
},
80+
},
81+
},
82+
}
83+
84+
// Propagate local proxy variables to the Job
85+
envVars = appendLocalEnvVar(envVars, "http_proxy")
86+
envVars = appendLocalEnvVar(envVars, "https_proxy")
87+
envVars = appendLocalEnvVar(envVars, "HTTPS_PROXY")
88+
envVars = appendLocalEnvVar(envVars, "no_proxy")
89+
envVars = appendLocalEnvVar(envVars, "NO_PROXY")
90+
91+
cmdString := fmt.Sprintf("/sysdig-inline-scan.sh --sysdig-url %s -d %s --registry-skip-tls --registry-auth-basic '%s' ", i.secureURL, req.Artifact.Digest, userPassword)
92+
// Add --sysdig-skip-tls only if insecure
93+
if !i.verifySSL {
94+
cmdString += "--sysdig-skip-tls "
95+
}
96+
97+
cmdString += getImageFrom(req)
6798
return &batchv1.Job{
6899
ObjectMeta: metav1.ObjectMeta{
69100
Name: name,
@@ -76,25 +107,13 @@ func (i *inlineAdapter) buildJob(req harbor.ScanRequest) *batchv1.Job {
76107
Containers: []corev1.Container{
77108
{
78109
Name: "scanner",
79-
Image: "sysdiglabs/sysdig-inline-scan:harbor-1.0",
110+
Image: "quay.io/sysdig/secure-inline-scan:2",
80111
Command: []string{"/bin/sh"},
81112
Args: []string{
82113
"-c",
83-
fmt.Sprintf("/sysdig-inline-scan.sh -s %s -k '$(SYSDIG_SECURE_API_TOKEN)' -d %s -P -n -u %s %s || true", i.secureURL, req.Artifact.Digest, userPassword, getImageFrom(req)),
84-
},
85-
Env: []corev1.EnvVar{
86-
{
87-
Name: "SYSDIG_SECURE_API_TOKEN",
88-
ValueFrom: &corev1.EnvVarSource{
89-
SecretKeyRef: &corev1.SecretKeySelector{
90-
LocalObjectReference: corev1.LocalObjectReference{
91-
Name: i.secret,
92-
},
93-
Key: "sysdig_secure_api_token",
94-
},
95-
},
96-
},
114+
fmt.Sprintf("%s || true", cmdString),
97115
},
116+
Env: envVars,
98117
},
99118
},
100119
},
@@ -103,6 +122,17 @@ func (i *inlineAdapter) buildJob(req harbor.ScanRequest) *batchv1.Job {
103122
}
104123
}
105124

125+
func appendLocalEnvVar(envVars []corev1.EnvVar, key string) []corev1.EnvVar {
126+
if value, exists := os.LookupEnv(key); exists {
127+
envVars = append(envVars, corev1.EnvVar{
128+
Name: key,
129+
Value: value,
130+
})
131+
}
132+
133+
return envVars
134+
}
135+
106136
func jobName(repository string, shaDigest string) string {
107137
return fmt.Sprintf(
108138
"inline-scan-%x",

pkg/scanner/inline_adapter_test.go

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ package scanner_test
22

33
import (
44
"context"
5-
"encoding/base64"
6-
"encoding/json"
7-
"strings"
8-
95
"github.com/golang/mock/gomock"
106
. "github.com/onsi/ginkgo"
117
. "github.com/onsi/gomega"
8+
"os"
129

1310
batchv1 "k8s.io/api/batch/v1"
1411
corev1 "k8s.io/api/core/v1"
@@ -31,6 +28,34 @@ const (
3128
resourceName = "inline-scan-1e668f7cc4c27e915cfed9793808357e"
3229
)
3330

31+
type envItem struct {
32+
value string
33+
defined bool
34+
}
35+
36+
func saveEnv(keys []string) map[string]envItem {
37+
envItems := make(map[string]envItem)
38+
for _, key := range keys {
39+
value, defined := os.LookupEnv(key)
40+
envItems[key] = envItem{
41+
value: value,
42+
defined: defined,
43+
}
44+
}
45+
46+
return envItems
47+
}
48+
49+
func restoreEnv(savedItems map[string]envItem) {
50+
for key, item := range savedItems {
51+
if item.defined {
52+
os.Setenv(key, item.value)
53+
} else {
54+
os.Unsetenv(key)
55+
}
56+
}
57+
}
58+
3459
var _ = Describe("InlineAdapter", func() {
3560
var (
3661
controller *gomock.Controller
@@ -43,7 +68,7 @@ var _ = Describe("InlineAdapter", func() {
4368
controller = gomock.NewController(GinkgoT())
4469
client = mocks.NewMockClient(controller)
4570
k8sClient = fake.NewSimpleClientset()
46-
inlineAdapter = scanner.NewInlineAdapter(client, k8sClient, secureURL, namespace, secret)
71+
inlineAdapter = scanner.NewInlineAdapter(client, k8sClient, secureURL, namespace, secret, true)
4772
})
4873

4974
AfterEach(func() {
@@ -65,6 +90,40 @@ var _ = Describe("InlineAdapter", func() {
6590
Expect(result).To(Equal(job()))
6691
})
6792

93+
It("proxy env vars are included in the Job environment", func() {
94+
95+
savedEnv := saveEnv([]string{"http_proxy", "https_proxy", "HTTPS_PROXY", "no_proxy", "NO_PROXY"})
96+
97+
os.Setenv("http_proxy", "http_proxy-value")
98+
os.Setenv("https_proxy", "https_proxy-value")
99+
os.Setenv("HTTPS_PROXY", "HTTPS_PROXY-value")
100+
os.Setenv("no_proxy", "no_proxy-value")
101+
os.Setenv("NO_PROXY", "NO_PROXY-value")
102+
103+
inlineAdapter.Scan(scanRequest())
104+
105+
restoreEnv(savedEnv)
106+
107+
result, _ := k8sClient.BatchV1().Jobs(namespace).Get(context.Background(), resourceName, metav1.GetOptions{})
108+
109+
Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "http_proxy", Value: "http_proxy-value"}))
110+
Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "https_proxy", Value: "https_proxy-value"}))
111+
Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "HTTPS_PROXY", Value: "HTTPS_PROXY-value"}))
112+
Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "no_proxy", Value: "no_proxy-value"}))
113+
Expect(result.Spec.Template.Spec.Containers[0].Env).To(ContainElement(corev1.EnvVar{Name: "NO_PROXY", Value: "NO_PROXY-value"}))
114+
})
115+
116+
It("adds --sysdig-skip-tls in insecure", func() {
117+
118+
inlineAdapter = scanner.NewInlineAdapter(client, k8sClient, secureURL, namespace, secret, false)
119+
120+
inlineAdapter.Scan(scanRequest())
121+
122+
result, _ := k8sClient.BatchV1().Jobs(namespace).Get(context.Background(), resourceName, metav1.GetOptions{})
123+
124+
Expect(result.Spec.Template.Spec.Containers[0].Args).To(ContainElement(ContainSubstring("--sysdig-skip-tls")))
125+
})
126+
68127
Context("when a job already exists", func() {
69128
It("returns the scanID for checking if scan has finished", func() {
70129
k8sClient.BatchV1().Jobs(namespace).Create(context.Background(), activeJob(), metav1.CreateOptions{})
@@ -121,19 +180,6 @@ var _ = Describe("InlineAdapter", func() {
121180
})
122181
})
123182

124-
func getUserAndPasswordFromSecret(k8sClient kubernetes.Interface, namespace string, name string) (string, string) {
125-
secret, _ := k8sClient.CoreV1().Secrets(namespace).Get(context.Background(), name, metav1.GetOptions{})
126-
127-
var parsed map[string]interface{}
128-
json.Unmarshal(secret.Data["config.json"], &parsed)
129-
130-
encodedCredentials := parsed["auths"].(map[string]interface{})["harbor.sysdig-demo.zone"].(map[string]interface{})["auth"].(string)
131-
basicAuthCredentials, _ := base64.StdEncoding.DecodeString(encodedCredentials)
132-
credentials := strings.Split(string(basicAuthCredentials), ":")
133-
134-
return credentials[0], credentials[1]
135-
}
136-
137183
func job() *batchv1.Job {
138184
jobTTL := int32(86400)
139185
return &batchv1.Job{
@@ -149,15 +195,15 @@ func job() *batchv1.Job {
149195
Containers: []corev1.Container{
150196
{
151197
Name: "scanner",
152-
Image: "sysdiglabs/sysdig-inline-scan:harbor-1.0",
198+
Image: "quay.io/sysdig/secure-inline-scan:2",
153199
Command: []string{"/bin/sh"},
154200
Args: []string{
155201
"-c",
156-
"/sysdig-inline-scan.sh -s https://secure.sysdig.com -k '$(SYSDIG_SECURE_API_TOKEN)' -d an image digest -P -n -u robot$9f6711d1-834d-11ea-867f-76103d08dca8:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTAwMDk5OTksImlhdCI6MTU4NzQxNzk5OSwiaXNzIjoiaGFyYm9yLXRva2VuLWRlZmF1bHRJc3N1ZXIiLCJpZCI6OSwicGlkIjoyLCJhY2Nlc3MiOlt7IlJlc291cmNlIjoiL3Byb2plY3QvMi9yZXBvc2l0b3J5IiwiQWN0aW9uIjoic2Nhbm5lci1wdWxsIiwiRWZmZWN0IjoiIn1dfQ.A3_aTzvxqSTvl26pQKa97ay15zRPC9K55NE0WbEyOsY3m0KFz-HuSDatncWLSYvOlcGVdysKlF3JXYWIjQ7tEI4V76WA9UMoi-fr9vEEdWLF5C1uWZJOz_S72sQ3G1BzsLp3HyWe9ZN5EBK9mhXzYNv2rONYrr0UJeBmNnMf2mU3sH71OO_G6JvRl5fwFSLSYx8nQs82PhfVhx50wRuWl_zyeCCDy_ytLzjRBvZwKuI9iVIxgM1pRfKG15NWMHfl0lcYnjm7f1_WFGKtVddkLOTICK0_FPtef1L8A16ozo_2NA32WD9PstdcTuD37XbZ6AFXUAZFoZLfCEW97mtIZBY2uYMwDQtc6Nme4o3Ya-MnBEIAs9Vi9d5a4pkf7Two-xjI-9ESgVz79YqL-_OnecQPNJ9yAFtJuxQ7StfsCIZx84hh5VdcZmW9jlezRHh4hTAjsNmrOBFTAjPyaXk98Se3Fj0Ev3bChod63og4frE7_fE7HnoBKVPHRAdBhJ2yrAiPymfij_kD4ke1Vb0AxmGGOwRP2K3TZNqEdKcq89lU6lHYV2UfrWchuF3u4ieNEC1BGu1_m_c55f0YZH1FAq6evCyA0JnFuXzO4cCxC7WHzXXRGSC9Lm3LF7cbaZAgFj5d34gbgUQmJst8nPlpW-KtwRL-pHC6mipunCBv9bU harbor.sysdig-demo.zone/sysdig/agent:9.7.0 || true",
202+
"/sysdig-inline-scan.sh --sysdig-url https://secure.sysdig.com -d an image digest --registry-skip-tls --registry-auth-basic 'robot$9f6711d1-834d-11ea-867f-76103d08dca8:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTAwMDk5OTksImlhdCI6MTU4NzQxNzk5OSwiaXNzIjoiaGFyYm9yLXRva2VuLWRlZmF1bHRJc3N1ZXIiLCJpZCI6OSwicGlkIjoyLCJhY2Nlc3MiOlt7IlJlc291cmNlIjoiL3Byb2plY3QvMi9yZXBvc2l0b3J5IiwiQWN0aW9uIjoic2Nhbm5lci1wdWxsIiwiRWZmZWN0IjoiIn1dfQ.A3_aTzvxqSTvl26pQKa97ay15zRPC9K55NE0WbEyOsY3m0KFz-HuSDatncWLSYvOlcGVdysKlF3JXYWIjQ7tEI4V76WA9UMoi-fr9vEEdWLF5C1uWZJOz_S72sQ3G1BzsLp3HyWe9ZN5EBK9mhXzYNv2rONYrr0UJeBmNnMf2mU3sH71OO_G6JvRl5fwFSLSYx8nQs82PhfVhx50wRuWl_zyeCCDy_ytLzjRBvZwKuI9iVIxgM1pRfKG15NWMHfl0lcYnjm7f1_WFGKtVddkLOTICK0_FPtef1L8A16ozo_2NA32WD9PstdcTuD37XbZ6AFXUAZFoZLfCEW97mtIZBY2uYMwDQtc6Nme4o3Ya-MnBEIAs9Vi9d5a4pkf7Two-xjI-9ESgVz79YqL-_OnecQPNJ9yAFtJuxQ7StfsCIZx84hh5VdcZmW9jlezRHh4hTAjsNmrOBFTAjPyaXk98Se3Fj0Ev3bChod63og4frE7_fE7HnoBKVPHRAdBhJ2yrAiPymfij_kD4ke1Vb0AxmGGOwRP2K3TZNqEdKcq89lU6lHYV2UfrWchuF3u4ieNEC1BGu1_m_c55f0YZH1FAq6evCyA0JnFuXzO4cCxC7WHzXXRGSC9Lm3LF7cbaZAgFj5d34gbgUQmJst8nPlpW-KtwRL-pHC6mipunCBv9bU' harbor.sysdig-demo.zone/sysdig/agent:9.7.0 || true",
157203
},
158204
Env: []corev1.EnvVar{
159205
{
160-
Name: "SYSDIG_SECURE_API_TOKEN",
206+
Name: "SYSDIG_API_TOKEN",
161207
ValueFrom: &corev1.EnvVarSource{
162208
SecretKeyRef: &corev1.SecretKeySelector{
163209
LocalObjectReference: corev1.LocalObjectReference{

pkg/secure/client.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ type Client interface {
3838
}
3939

4040
func NewClient(apiToken string, secureURL string, verifySSL bool) Client {
41+
// Clone DefaultTransport to use proxy settings and default timeouts
42+
transport := http.DefaultTransport.(*http.Transport).Clone()
43+
44+
if !verifySSL {
45+
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
46+
}
47+
4148
return &client{
4249
apiToken: apiToken,
4350
secureURL: secureURL,
44-
client: http.Client{
45-
Transport: &http.Transport{
46-
TLSClientConfig: &tls.Config{
47-
InsecureSkipVerify: verifySSL,
48-
},
49-
},
50-
},
51+
client: http.Client{Transport: transport},
5152
}
5253
}
5354

0 commit comments

Comments
 (0)