diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000000..24fcbf8386 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,78 @@ +name: build-image + +on: + workflow_dispatch: + inputs: + IMAGE_TAG: + required: true + type: string + description: "Image tag for the node-agent image" + STORAGE_REF: + required: false + type: string + default: "" + description: "Branch/tag/commit of k8sstormcenter/storage to use (leave empty to keep go.mod default)" + PLATFORMS: + type: boolean + required: false + default: false + description: "Build for both amd64 and arm64" + +jobs: + build: + runs-on: ubuntu-latest + permissions: + id-token: write + packages: write + contents: read + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: actions/setup-go@v5 + with: + go-version: "1.25" + + - name: Update storage dependency + if: ${{ inputs.STORAGE_REF != '' }} + env: + STORAGE_REF: ${{ inputs.STORAGE_REF }} + run: | + echo "Replacing github.com/kubescape/storage with github.com/k8sstormcenter/storage@${STORAGE_REF}" + go mod edit -replace "github.com/kubescape/storage=github.com/k8sstormcenter/storage@${STORAGE_REF}" + GOPROXY=direct GONOSUMCHECK="github.com/k8sstormcenter/*" go mod tidy + echo "Resolved storage version:" + grep "k8sstormcenter/storage" go.sum | head -1 + + - name: Ensure ig is installed + run: | + curl -L https://github.com/inspektor-gadget/inspektor-gadget/releases/download/v0.45.0/ig_0.45.0_amd64.deb -O + sudo dpkg -i ig_0.45.0_amd64.deb + + - name: Build gadgets + run: make gadgets + + - name: Set up QEMU + if: ${{ inputs.PLATFORMS }} + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: build/Dockerfile + tags: ghcr.io/${{ github.repository_owner }}/node-agent:${{ inputs.IMAGE_TAG }} + build-args: image_version=${{ inputs.IMAGE_TAG }} + platforms: ${{ inputs.PLATFORMS && 'linux/amd64,linux/arm64' || 'linux/amd64' }} + push: true diff --git a/.github/workflows/bypass.yaml b/.github/workflows/bypass.yaml index 49b38b42c5..be81f0260b 100644 --- a/.github/workflows/bypass.yaml +++ b/.github/workflows/bypass.yaml @@ -20,7 +20,7 @@ jobs: needs: reset-run-number uses: ./.github/workflows/incluster-comp-pr-merged.yaml with: - IMAGE_NAME: quay.io/${{ github.repository_owner }}/node-agent + IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/node-agent IMAGE_TAG: v0.2.${{ needs.reset-run-number.outputs.run-number }} COMPONENT_NAME: nodeAgent CGO_ENABLED: 0 diff --git a/.github/workflows/component-tests.yaml b/.github/workflows/component-tests.yaml index e1dfeea907..91d0778d2b 100644 --- a/.github/workflows/component-tests.yaml +++ b/.github/workflows/component-tests.yaml @@ -2,6 +2,13 @@ name: Node Agent Component Tests on: pull_request: types: [synchronize, ready_for_review, opened, reopened] + workflow_dispatch: + inputs: + build_image: + description: 'Build and push a new container image for the test' + type: boolean + required: false + default: false concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -9,16 +16,23 @@ concurrency: jobs: build-and-push-image: + # Only run this job if it's a manual trigger with the box checked. + if: github.event_name == 'workflow_dispatch' && github.event.inputs.build_image == true runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write steps: - name: Checkout code uses: actions/checkout@v4 - - name: Login to Quay.io + - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: - registry: quay.io/kubescape - username: ${{ secrets.QUAYIO_REGISTRY_USERNAME }} - password: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Install IG run: | sudo apt-get update @@ -33,9 +47,9 @@ jobs: run: | COMMIT_HASH=$(git rev-parse --short HEAD) export IMAGE_TAG=test-${COMMIT_HASH} - export IMAGE_REPO=quay.io/kubescape/node-agent + export IMAGE_REPO=ghcr.io/${{ github.repository_owner }}/node-agent echo "image_repo=${IMAGE_REPO}" >> "$GITHUB_OUTPUT" - export IMAGE_NAME=quay.io/kubescape/node-agent:${IMAGE_TAG} + export IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/node-agent:${IMAGE_TAG} echo "image_tag=${IMAGE_TAG}" >> "$GITHUB_OUTPUT" make docker-build TAG=${IMAGE_TAG} IMAGE=${IMAGE_REPO} && make docker-push TAG=${IMAGE_TAG} IMAGE=${IMAGE_REPO} outputs: @@ -44,7 +58,6 @@ jobs: component-tests: runs-on: ubuntu-latest - needs: build-and-push-image continue-on-error: true strategy: matrix: @@ -72,6 +85,7 @@ jobs: Test_22_AlertOnPartialNetworkProfileTest, Test_23_RuleCooldownTest, Test_24_ProcessTreeDepthTest + Test_27_RegexFileOpenMatchTest ] steps: - name: Checkout code @@ -101,7 +115,11 @@ jobs: run: | STORAGE_TAG=$(./tests/scripts/storage-tag.sh) echo "Storage tag that will be used: ${STORAGE_TAG}" - helm upgrade --install kubescape ./tests/chart --set clusterName=`kubectl config current-context` --set nodeAgent.image.tag=${{ needs.build-and-push-image.outputs.image_tag }} --set nodeAgent.image.repository=${{ needs.build-and-push-image.outputs.image_repo }} --set storage.image.tag=${STORAGE_TAG} -n kubescape --create-namespace --wait --timeout 5m --debug + IMAGE_TAG="latest" + IMAGE_REPO='ghcr.io/k8sstormcenter/node-agent' + echo "Using Node Agent image: ${IMAGE_REPO}:${IMAGE_TAG}" + # End of constanze modification + helm upgrade --install kubescape ./tests/chart --set clusterName=`kubectl config current-context` --set nodeAgent.image.tag=${IMAGE_TAG} --set nodeAgent.image.repository=${IMAGE_REPO} --set storage.image.tag=${STORAGE_TAG} -n kubescape --create-namespace --wait --timeout 5m --debug # Check that the node-agent pod is running kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name=node-agent -n kubescape --timeout=300s sleep 5 diff --git a/.github/workflows/incluster-comp-pr-merged.yaml b/.github/workflows/incluster-comp-pr-merged.yaml index 89a0fa52dc..fe6f59afb8 100644 --- a/.github/workflows/incluster-comp-pr-merged.yaml +++ b/.github/workflows/incluster-comp-pr-merged.yaml @@ -109,12 +109,12 @@ jobs: id: unit-test run: go test -exec sudo -v ./... - - name: Login to Quay + - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: - registry: quay.io - username: ${{ secrets.QUAYIO_REGISTRY_USERNAME }} - password: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v6 @@ -349,12 +349,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to Quay + - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: - registry: quay.io - username: ${{ secrets.QUAYIO_REGISTRY_USERNAME }} - password: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Docker retag run: | diff --git a/.github/workflows/pr-created.yaml b/.github/workflows/pr-created.yaml index 856fa2bc26..76ad4f3cbf 100644 --- a/.github/workflows/pr-created.yaml +++ b/.github/workflows/pr-created.yaml @@ -13,6 +13,10 @@ concurrency: jobs: pr-created: + permissions: + pull-requests: write + security-events: write + contents: read uses: ./.github/workflows/incluster-comp-pr-created.yaml with: GO_VERSION: "1.25" diff --git a/.github/workflows/pr-merged.yaml b/.github/workflows/pr-merged.yaml index 2d0d5ba4b5..38163ad470 100644 --- a/.github/workflows/pr-merged.yaml +++ b/.github/workflows/pr-merged.yaml @@ -29,7 +29,7 @@ jobs: needs: reset-run-number uses: ./.github/workflows/incluster-comp-pr-merged.yaml with: - IMAGE_NAME: quay.io/${{ github.repository_owner }}/node-agent + IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/node-agent IMAGE_TAG: v0.3.${{ needs.reset-run-number.outputs.run-number }} COMPONENT_NAME: nodeAgent CGO_ENABLED: 0 diff --git a/tests/chart/values.yaml b/tests/chart/values.yaml index 7cf029c4c8..cde97df906 100644 --- a/tests/chart/values.yaml +++ b/tests/chart/values.yaml @@ -32,7 +32,7 @@ global: storage: name: "storage" image: - repository: quay.io/kubescape/storage + repository: ghcr.io/k8sstormcenter/storage tag: v0.0.156 pullPolicy: Always cleanupInterval: "6h" @@ -50,7 +50,7 @@ storage: nodeAgent: name: node-agent image: - repository: quay.io/kubescape/node-agent + repository: ghcr.io/k8sstormcenter/node-agent tag: v0.2.21 pullPolicy: IfNotPresent diff --git a/tests/component_test.go b/tests/component_test.go index cdede98ff5..761cca7a16 100644 --- a/tests/component_test.go +++ b/tests/component_test.go @@ -1565,3 +1565,76 @@ func Test_24_ProcessTreeDepthTest(t *testing.T) { t.Logf("Found alerts for the process tree depth: %v", alerts) } + +func Test_27_RegexFileOpenMatchTest(t *testing.T) { + start := time.Now() + defer tearDownTest(t, start) + + t.Log("Starting regex file open match component test") + + // 1. Setup workload and initial profile + ns := testutils.NewRandomNamespace() + wl, err := testutils.NewTestWorkload(ns.Name, path.Join(utils.CurrentDir(), "resources/nginx-deployment.yaml")) + require.NoError(t, err, "Failed to create workload") + require.NoError(t, wl.WaitForReady(80), "Workload failed to be ready") + require.NoError(t, wl.WaitForApplicationProfileCompletion(80), "Application profile did not complete") + + // Wait for the initial profile to be processed + time.Sleep(30 * time.Second) + + initialProfile, err := wl.GetApplicationProfile() + require.NoError(t, err, "Failed to get initial profile") + + // 2. Apply a user-managed profile with a regex rule for file opens + t.Log("Applying user-managed profile...") + // Create the user-managed profile + userProfile := &v1beta1.ApplicationProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("ug-%s", initialProfile.Name), + Namespace: initialProfile.Namespace, + Annotations: map[string]string{ + "kubescape.io/managed-by": "User", + }, + }, + Spec: v1beta1.ApplicationProfileSpec{ + Architectures: []string{"amd64"}, + Containers: []v1beta1.ApplicationProfileContainer{ + { + Name: "nginx", + Execs: []v1beta1.ExecCalls{ + { + Path: "/usr/bin/ls", + Args: []string{"/usr/bin/ls", "-l"}, + }, + }, + Opens: []v1beta1.OpenCalls{ + {Path: "/etc/nginx/*", Flags: []string{"O_RDONLY"}}, + {Path: "/var/log/nginx/*", Flags: []string{"O_WRONLY", "O_CREAT"}}, + }, + }, + }, + }, + } + + // Create the user-managed profile + k8sClient := k8sinterface.NewKubernetesApi() + storageClient := spdxv1beta1client.NewForConfigOrDie(k8sClient.K8SConfig) + _, err = storageClient.ApplicationProfiles(ns.Name).Create(context.Background(), userProfile, metav1.CreateOptions{}) + require.NoError(t, err, "Failed to create user profile") + + // Wait for the user profile to be processed by the system + time.Sleep(60 * time.Second) + + // 3. Trigger file open events to test the regex rule + t.Log("Triggering file open events to test regex rule") + _, _, _ = wl.ExecIntoPod([]string{"cat", "/etc/nginx/nginx.conf"}, "nginx") // Should be allowed by regex + _, _, _ = wl.ExecIntoPod([]string{"cat", "/etc/hostname"}, "nginx") // Should be blocked (alert) + + time.Sleep(30 * time.Second) // Wait for alerts + + // 4. Verify alerts + alerts, err := testutils.GetAlerts(wl.Namespace) + require.NoError(t, err, "Failed to get alerts") + testutils.AssertNotContains(t, alerts, "Unexpected file open", "cat", "nginx", []bool{true}) + testutils.AssertContains(t, alerts, "Unexpected file open", "cat", "hostname", []bool{true}) +} diff --git a/tests/scripts/storage-tag.sh b/tests/scripts/storage-tag.sh index 5512f2ae5a..3d23046b20 100755 --- a/tests/scripts/storage-tag.sh +++ b/tests/scripts/storage-tag.sh @@ -1,4 +1,4 @@ #/bin/bash -curl -s https://raw.githubusercontent.com/kubescape/helm-charts/main/charts/kubescape-operator/values.yaml -o values.yaml +curl -s https://raw.githubusercontent.com/bob/test/localtestbuild/kubescape/values.yaml -o values.yaml yq '.storage.image.tag' < values.yaml rm -rf values.yaml