Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ require (
github.com/stackrox/anchore-client v0.0.0-20190929180200-981e05834836
github.com/stackrox/default-authz-plugin v0.0.0-20210608105219-00ad9c9f3855
github.com/stackrox/external-network-pusher v0.0.0-20210419192707-074af92bbfa7
github.com/stackrox/helmtest v0.0.0-20211118112901-c6fc838e7f89
github.com/stackrox/helmtest v0.0.0-20220103101722-9f16fec5b1f6
github.com/stackrox/k8s-istio-cve-pusher v0.0.0-20210422200002-d89f671ac4f5
github.com/steveyen/gtreap v0.1.0 // indirect
github.com/stretchr/testify v1.7.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1928,8 +1928,8 @@ github.com/stackrox/external-network-pusher v0.0.0-20210419192707-074af92bbfa7 h
github.com/stackrox/external-network-pusher v0.0.0-20210419192707-074af92bbfa7/go.mod h1:faUw9vx/mA7ql41Ftlst5MYar2DT3nnS6oK94lbaW0g=
github.com/stackrox/helm-operator v0.0.8-0.20211217081542-57dfe5d681e3 h1:O96olg7oQXTbQUbXdrDPkrT9WjesGI+3bq5H8cjmsxo=
github.com/stackrox/helm-operator v0.0.8-0.20211217081542-57dfe5d681e3/go.mod h1:u5rkZgJvT0MfanZCoq/lCqY+3Ixr+CbPxYNnhvsggHg=
github.com/stackrox/helmtest v0.0.0-20211118112901-c6fc838e7f89 h1:h3Z1bazS+4RWhzDk4L3B/jN4DL0UAZCDCx7UfQ6T5jg=
github.com/stackrox/helmtest v0.0.0-20211118112901-c6fc838e7f89/go.mod h1:+BKUQnSVJqDJr4sa8zmCKyQ/UOjJuy/frPEyZnTrigY=
github.com/stackrox/helmtest v0.0.0-20220103101722-9f16fec5b1f6 h1:xLOTCeLZk9fj7WwAxQgqp9X4u1WyoaLlFMKcivXYznM=
github.com/stackrox/helmtest v0.0.0-20220103101722-9f16fec5b1f6/go.mod h1:+BKUQnSVJqDJr4sa8zmCKyQ/UOjJuy/frPEyZnTrigY=
github.com/stackrox/k8s-cves v0.0.0-20201110001126-cc333981eaab h1:77xJmm1YkqbgrQzHI3C4MyPckWL+PYRLWakQRC6Mzj8=
github.com/stackrox/k8s-cves v0.0.0-20201110001126-cc333981eaab/go.mod h1:EBskgGC5Gzt/r8ToNsuD6tYMcf+AWY0ubaFSRy5/3QM=
github.com/stackrox/k8s-istio-cve-pusher v0.0.0-20210422200002-d89f671ac4f5 h1:0O3kYf9IvjnzwKBE/UuofeiKmwb8x9ga3mm26dqL4/Y=
Expand Down
194 changes: 193 additions & 1 deletion pkg/helm/charts/tests/securedclusterservices/helmtest_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package securedclusterservices

import (
"fmt"
"testing"

helmTest "github.com/stackrox/helmtest/pkg/framework"
"github.com/stackrox/rox/image"
"github.com/stackrox/rox/image/sensor"
"github.com/stackrox/rox/pkg/env"
"github.com/stackrox/rox/pkg/helm/charts"
metaUtil "github.com/stackrox/rox/pkg/helm/charts/testutils"
"github.com/stackrox/rox/pkg/images/defaults"
"github.com/stackrox/rox/pkg/images/utils"
"github.com/stackrox/rox/pkg/urlfmt"
"github.com/stackrox/rox/pkg/version"
"github.com/stretchr/testify/require"
"helm.sh/helm/v3/pkg/chartutil"
)
Expand All @@ -17,7 +25,191 @@ func TestWithHelmtest(t *testing.T) {
ch, err := tpl.InstantiateAndLoad(metaUtil.MakeMetaValuesForTest(t))
require.NoError(t, err, "error instantiating chart")

suite, err := helmTest.NewLoader("testdata/helmtest").LoadSuite()
suite, err := helmTest.NewLoader("testdata/helmtest/chart").LoadSuiteWithFlavour("chart")
require.NoError(t, err, "failed to load helmtest suite")

target := &helmTest.Target{
Chart: ch,
ReleaseOptions: chartutil.ReleaseOptions{
Name: "stackrox-secured-cluster-services",
Namespace: "stackrox",
IsInstall: true,
},
}
suite.Run(t, target)
}

func TestBundleWithHelmtest(t *testing.T) {
caCert := []byte(`
-----BEGIN CERTIFICATE-----
MIIB0jCCAXigAwIBAgIUDuyxeeW/uPhPXh1VEkEoy8k5qScwCgYIKoZIzj0EAwIw
RzEnMCUGA1UEAxMeU3RhY2tSb3ggQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRwwGgYD
VQQFExMyNjEwMTE1MzMwMjg0NTM5ODcxMB4XDTIxMTIxMDA5MDQwMFoXDTI2MTIw
OTA5MDQwMFowRzEnMCUGA1UEAxMeU3RhY2tSb3ggQ2VydGlmaWNhdGUgQXV0aG9y
aXR5MRwwGgYDVQQFExMyNjEwMTE1MzMwMjg0NTM5ODcxMFkwEwYHKoZIzj0CAQYI
KoZIzj0DAQcDQgAEPVQ/Oyg9OuGkbLdfzFIkoRq55DI0RCcQyXW4FNzkjyYiheIQ
M40nX8OrqNKl19kQ+2aha5AnfNPz8+xESz/F6qNCMEAwDgYDVR0PAQH/BAQDAgEG
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqCTvxyQ23AP9zccrKlNZE1HIAo
MAoGCCqGSM49BAMCA0gAMEUCIQDWfGn2/X259pOne8wKikNQV3SIcJOWqb+Qx7Gf
ZgNtGQIgOon9+aGqGUzTONWJM26nEG+9/pnbc0QYHIJzgZIk7Ps=
-----END CERTIFICATE-----
`)
admissionControllerCert := []byte(`
-----BEGIN CERTIFICATE-----
MIICkjCCAjegAwIBAgIIA9dIbqpbG3YwCgYIKoZIzj0EAwIwRzEnMCUGA1UEAxMe
U3RhY2tSb3ggQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRwwGgYDVQQFExMyNjEwMTE1
MzMwMjg0NTM5ODcxMB4XDTIxMTIxMDA4MTIwMFoXDTIyMTIxMDA5MTIwMFowgYsx
IjAgBgNVBAsMGUFETUlTU0lPTl9DT05UUk9MX1NFUlZJQ0UxSDBGBgNVBAMMP0FE
TUlTU0lPTl9DT05UUk9MX1NFUlZJQ0U6IDIxOWFkMmViLWYxOTUtNDZjNi1iYjgy
LTliOTM4MWVmZDExNTEbMBkGA1UEBRMSMjc2NzY5NTQyMjQ4Mjc0ODA2MFkwEwYH
KoZIzj0CAQYIKoZIzj0DAQcDQgAEUcXy4PQpeNU72NGwxcKGw1r7NUNIzTIBveU/
rhKyQ5DUAgycAwJxWUlNVRU2jy+GWYDrG1+XDgoFPpFBrEOqVqOBxzCBxDAOBgNV
HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
EwEB/wQCMAAwHQYDVR0OBBYEFAF7GFtqB4kUi2QaInVSDvvEPI0/MB8GA1UdIwQY
MBaAFPqCTvxyQ23AP9zccrKlNZE1HIAoMEUGA1UdEQQ+MDyCGmFkbWlzc2lvbi1j
b250cm9sLnN0YWNrcm94gh5hZG1pc3Npb24tY29udHJvbC5zdGFja3JveC5zdmMw
CgYIKoZIzj0EAwIDSQAwRgIhALc0O1ayC4YlPT8t2QJ14hnjOEbQp5oQZANfa9iR
MSddAiEAlQgi9q89EFXbd7LcBfgL6Gm3Re1VRNbO+BA0rB3OThI=
-----END CERTIFICATE-----
`)
admissionControllerKey := []byte(`
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIG13qSEw6Ic1VNVXwcr5QLkF93mFwdSLFxAlFqdfPoIsoAoGCCqGSM49
AwEHoUQDQgAEUcXy4PQpeNU72NGwxcKGw1r7NUNIzTIBveU/rhKyQ5DUAgycAwJx
WUlNVRU2jy+GWYDrG1+XDgoFPpFBrEOqVg==
-----END EC PRIVATE KEY-----
`)
collectorCert := []byte(`
-----BEGIN CERTIFICATE-----
MIICdDCCAhmgAwIBAgIJAO79iFeyz9WoMAoGCCqGSM49BAMCMEcxJzAlBgNVBAMT
HlN0YWNrUm94IENlcnRpZmljYXRlIEF1dGhvcml0eTEcMBoGA1UEBRMTMjYxMDEx
NTMzMDI4NDUzOTg3MTAeFw0yMTEyMTAwODEyMDBaFw0yMjEyMTAwOTEyMDBaMH0x
GjAYBgNVBAsMEUNPTExFQ1RPUl9TRVJWSUNFMUAwPgYDVQQDDDdDT0xMRUNUT1Jf
U0VSVklDRTogMjE5YWQyZWItZjE5NS00NmM2LWJiODItOWI5MzgxZWZkMTE1MR0w
GwYDVQQFExQxNzIyMTA3MDQ2MDM3ODE0MjEyMDBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABDh3DcVf1bzJ9Lb21mQcfhl23Vx7IVVQPIJuIBb6qtbSdyhWa73/eK8O
kcdsGo7oRhSx/xx4Fm6VQfc7+EYk2vWjgbcwgbQwDgYDVR0PAQH/BAQDAgWgMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1Ud
DgQWBBTYXW+ei03m+YiPGH5uk/js0pw1xTAfBgNVHSMEGDAWgBT6gk78ckNtwD/c
3HKypTWRNRyAKDA1BgNVHREELjAsghJjb2xsZWN0b3Iuc3RhY2tyb3iCFmNvbGxl
Y3Rvci5zdGFja3JveC5zdmMwCgYIKoZIzj0EAwIDSQAwRgIhAPCNNnrFcw2fCGSf
09UOcm6ubWA/dMoefFT7LxnELTbDAiEAw/LMeJVYJgax75FQKu8LZ26irukkK+uT
X0DijvhIVPU=
-----END CERTIFICATE-----
`)
collectorKey := []byte(`
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBQE9SO1Smj0Hz8lXQmo/wCQqJiFFOPp1DOXS02vGH8HoAoGCCqGSM49
AwEHoUQDQgAEOHcNxV/VvMn0tvbWZBx+GXbdXHshVVA8gm4gFvqq1tJ3KFZrvf94
rw6Rx2wajuhGFLH/HHgWbpVB9zv4RiTa9Q==
-----END EC PRIVATE KEY-----
`)
sensorCert := []byte(`
-----BEGIN CERTIFICATE-----
MIICgzCCAiigAwIBAgIIGwUidvXyk3kwCgYIKoZIzj0EAwIwRzEnMCUGA1UEAxMe
U3RhY2tSb3ggQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRwwGgYDVQQFExMyNjEwMTE1
MzMwMjg0NTM5ODcxMB4XDTIxMTIxMDA4MTIwMFoXDTIyMTIxMDA5MTIwMFowdjEX
MBUGA1UECwwOU0VOU09SX1NFUlZJQ0UxPTA7BgNVBAMMNFNFTlNPUl9TRVJWSUNF
OiAyMTlhZDJlYi1mMTk1LTQ2YzYtYmI4Mi05YjkzODFlZmQxMTUxHDAaBgNVBAUT
EzE5NDcwMDAzMDgyMzU0MDgyNDkwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASp
nT9o6DX7B+wbX7erGTUz2TPQLLgSZlmwGlNdgjHumNSzixK6we2qo5M0RMFzhTqz
xZ4YtIbAzNqRNwrT9O4io4HOMIHLMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUuBs9
eWeUoldJ4w7m+wTHYpDsPEUwHwYDVR0jBBgwFoAU+oJO/HJDbcA/3NxysqU1kTUc
gCgwTAYDVR0RBEUwQ4IPc2Vuc29yLnN0YWNrcm94ghNzZW5zb3Iuc3RhY2tyb3gu
c3ZjghtzZW5zb3Itd2ViaG9vay5zdGFja3JveC5zdmMwCgYIKoZIzj0EAwIDSQAw
RgIhAJQqpyNLFCBsG2gl3k7tdsKDuGYjtnNrkfOyfi00JobmAiEAhyHSlGqeyz00
CVkGFtxky4vqF6TfDxn7sIcXuXmosG4=
-----END CERTIFICATE-----
`)
sensorKey := []byte(`
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAQWvW0FJ7lw5c10xVvbfvTFByDbprgI9WUGMt1KhsuDoAoGCCqGSM49
AwEHoUQDQgAEqZ0/aOg1+wfsG1+3qxk1M9kz0Cy4EmZZsBpTXYIx7pjUs4sSusHt
qqOTNETBc4U6s8WeGLSGwMzakTcK0/TuIg==
-----END EC PRIVATE KEY-----
`)
certs := sensor.Certs{
Files: map[string][]byte{
"admission-control-cert.pem": admissionControllerCert,
"admission-control-key.pem": admissionControllerKey,
"ca.pem": caCert,
"collector-cert.pem": collectorCert,
"collector-key.pem": collectorKey,
"sensor-cert.pem": sensorCert,
"sensor-key.pem": sensorKey,
},
}
mainImage, err := utils.GenerateImageFromStringWithDefaultTag("stackrox.io/stackrox/main", version.GetMainVersion())
require.NoError(t, err, "generating main image name")
mainImageName := mainImage.GetName()
collectorImage, err := utils.GenerateImageFromStringWithDefaultTag("stackrox.io/stackrox/collector", version.GetCollectorVersion())
require.NoError(t, err, "generating collector container image name")
collectorImageName := collectorImage.GetName()

centralEndpoint := "central.stackrox:8000"
collectionMethod := "EBPF"

chartMetaValues := charts.MetaValues{
"ClusterName": "test-sensor",
"ClusterType": "KUBERNETES",

"ImageRegistry": urlfmt.FormatURL(mainImageName.GetRegistry(), urlfmt.NONE, urlfmt.NoTrailingSlash),
"MainRegistry": urlfmt.FormatURL(mainImageName.GetRegistry(), urlfmt.NONE, urlfmt.NoTrailingSlash),
"ImageRemote": mainImageName.GetRemote(),
"ImageTag": mainImageName.GetTag(),

"PublicEndpoint": urlfmt.FormatURL(centralEndpoint, urlfmt.NONE, urlfmt.NoTrailingSlash),
"AdvertisedEndpoint": urlfmt.FormatURL(env.AdvertisedEndpoint.Setting(), urlfmt.NONE, urlfmt.NoTrailingSlash),

"CollectorRegistry": urlfmt.FormatURL(collectorImageName.GetRegistry(), urlfmt.NONE, urlfmt.NoTrailingSlash),
"CollectorImageRemote": collectorImageName.GetRemote(),
"CollectorFullImageTag": fmt.Sprintf("%s-latest", collectorImageName.GetTag()),
"CollectorFullImageRemote": collectorImageName.GetRemote(),
"CollectorSlimImageRemote": collectorImageName.GetRemote(),
"CollectorSlimImageTag": fmt.Sprintf("%s-slim", collectorImageName.GetTag()),
"CollectionMethod": collectionMethod,

// Hardcoding RHACS charts repo for now.
// TODO: fill ChartRepo based on the current image flavor.
"ChartRepo": defaults.ChartRepo{
URL: "http://mirror.openshift.com/pub/rhacs/charts",
},

"TolerationsEnabled": true,
"CreateUpgraderSA": true,

"EnvVars": map[string]interface{}{},

"K8sCommand": "kubectl",

"OfflineMode": env.OfflineModeEnv.BooleanSetting(),

"SlimCollector": true,

"KubectlOutput": true,

"Versions": version.GetAllVersions(),

"FeatureFlags": make(map[string]string),

"AdmissionController": true,
"AdmissionControlListenOnUpdates": true,
"AdmissionControlListenOnEvents": true,
"DisableBypass": true,
"TimeoutSeconds": 10,
"ScanInline": true,
"AdmissionControllerEnabled": true,
"AdmissionControlEnforceOnUpdates": true,
}

helmImage := image.GetDefaultImage()
tpl, err := helmImage.GetSecuredClusterServicesChartTemplate()
require.NoError(t, err, "error retrieving chart template")
ch, err := tpl.InstantiateAndLoadWithAdditionalFiles(chartMetaValues, certs.Files)
require.NoError(t, err, "error instantiating chart")

suite, err := helmTest.NewLoader("testdata/helmtest/bundle").LoadSuiteWithFlavour("bundle")
require.NoError(t, err, "failed to load helmtest suite")

target := &helmTest.Target{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defs: |
def container(obj; name):
obj.spec.template.spec.containers[] | select(.name == name);

def rawEnvVars(obj; container):
[container(obj; container) | .env[] | (.value = del(.name))] | from_entries;

def envVars(obj; container):
container(obj; container) | .env | from_entries;

def verifyNamespace(ns):
[.objects[].metadata | select(.namespace and .namespace != ns)] | assertThat(length == 0);

def helmClusterConfig:
.secrets["helm-cluster-config"] | .stringData["config.yaml"] | fromyaml;

def verifyCentralEndpoint(ep):
[
(envVars(.deployments.sensor; "sensor")["ROX_CENTRAL_ENDPOINT"] | assertThat(. == ep)),
(.secrets["helm-cluster-config"] | .stringData["config.yaml"] | fromyaml
| .clusterConfig.staticConfig.centralApiEndpoint | assertThat(. == ep))
][];

def verifySensorEndpoint(ep):
[
(envVars(.deployments["admission-control"]; "admission-control")["ROX_SENSOR_ENDPOINT"]
| assertThat(. == ep)),
(envVars(.daemonsets.collector; "collector")["GRPC_SERVER"] | assertThat(. == ep)),
(envVars(.daemonsets.collector; "compliance")["ROX_ADVERTISED_ENDPOINT"]
| assertThat(. == ep))
][];

def verifyMonitoringExposed(service):
[service.spec.ports[] | select(.name == "monitoring" and .port == 9090 and .targetPort == "monitoring")]
| (length == 1);

def verifyMonitoringContainerPortExposed(container):
[container | if .ports != null then .ports[] else {} end
| select(.containerPort == 9090 and .name == "monitoring")]
| (length == 1);

server:
visibleSchemas:
- kubernetes-1.20.2
values:
cluster:
name: "testcluster"
imagePullSecrets:
allowNone: true
config:
createSecrets: false
ca:
cert: "DUMMY CA CERTIFICATE"
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ defs: |

server:
visibleSchemas:
- kubernetes-1.20.2
- kubernetes-1.20.2
values:
clusterName: "testcluster"
imagePullSecrets:
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
tests:
- name: "cluster name secret is created on installation"
Release:
IsInstall: true
Condition:
IfFlavour: chart
values:
clusterName: test
expect: |
.secrets["helm-effective-cluster-name"] | assertThat(. != null)
(container(.deployments.sensor; "sensor")).volumeMounts[] | select(.name == "helm-effective-cluster-name") | assertThat(. != null)
.deployments.sensor.spec.template.spec.volumes[] | select(.name == "helm-effective-cluster-name") | assertThat(. != null)
- name: "cluster name secret is created on installation"
Release:
IsInstall: true
Condition:
IfFlavour: bundle
values:
cluster:
name: test
expect: |
.secrets["helm-effective-cluster-name"] | assertThat(. != null)
23 changes: 23 additions & 0 deletions pkg/helm/template/chart_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,26 @@ func (t *ChartTemplate) InstantiateAndLoad(metaVals charts.MetaValues) (*chart.C

return ch, nil
}

// InstantiateAndLoadWithAdditionalFiles is like InstantiateAndLoad but also allows injecting additionalFiles
// into the resulting chart.
func (t *ChartTemplate) InstantiateAndLoadWithAdditionalFiles(metaVals charts.MetaValues, additionalFiles map[string][]byte) (*chart.Chart, error) {
instantiatedFiles, err := t.InstantiateRaw(metaVals)
if err != nil {
return nil, errors.Wrap(err, "instantiating chart template files")
}

for path, data := range additionalFiles {
instantiatedFiles = append(instantiatedFiles, &loader.BufferedFile{
Name: path,
Data: data,
})
}

ch, err := loader.LoadFiles(instantiatedFiles)
if err != nil {
return nil, errors.Wrap(err, "loading instantiated chart files")
}

return ch, nil
}