Why DevSecOps looks different on Scaleway
Teams that move to Scaleway usually do so for two reasons: European data residency and a pricing model that stays predictable. What they often discover afterwards is that the security tooling ecosystem is thinner than on the hyperscalers. There is no managed equivalent of Amazon Inspector or Google Security Command Center that will silently scan your images and workloads for you. Scaleway gives you excellent primitives — IAM with applications and policies, Secret Manager, Private Networks, Audit Trail, Cockpit for observability, Kapsule for managed Kubernetes — but the assembly is yours.
That is not a drawback. It forces the security controls into the place where they belong: the delivery pipeline, versioned alongside the code. This article describes a concrete DevSecOps chain built around SAST, SCA, IaC scanning and DAST on Scaleway, with the trade-offs that matter when you actually have to run it every day.
The four families of scanning, and what each is actually good at
Before wiring anything into CI, be honest about what each class of tool detects. Most failed DevSecOps rollouts come from expecting SAST to find business logic flaws, or DAST to catch a vulnerable transitive dependency.
| Control | What it finds | Where it runs | Noise level | Blocking policy |
|---|---|---|---|---|
| Secret scanning | Committed API keys, Scaleway secret keys, tokens | Pre-commit + every push | Very low | Block immediately |
| SAST | Injection patterns, unsafe deserialization, weak crypto, path traversal | Merge request | Medium to high | Block on new HIGH findings only |
| SCA | Known CVEs in dependencies and base images | MR + nightly rescan | Low, but high volume | Block on fixable HIGH/CRITICAL |
| IaC scanning | Public security groups, unencrypted volumes, over-broad IAM policies | MR on the infra repo | Low | Block on HIGH |
| DAST | Auth bypass, misconfigured headers, exposed endpoints, real-world exploitability | Ephemeral review env | Medium | Report first, block later |
Note the last column. A pipeline that blocks on everything from day one gets bypassed within a fortnight. Start with secrets and IaC as hard gates — they are cheap and almost noise-free — then progressively harden SAST and SCA using a diff-based approach where only findings introduced by the merge request cause a failure.
SAST that developers do not disable
Semgrep has become the pragmatic default for polyglot codebases: rules are readable YAML, the community ruleset covers most languages, and semgrep ci natively performs a diff scan against the target branch. SonarQube remains relevant if you already run it for code quality and want a single quality gate, but its container needs a database and a Scaleway Instance or a Kapsule deployment to host it — a real operational cost. For narrower stacks, language-native tools (gosec, Bandit, Brakeman) are faster and produce fewer false positives.
Two rules make SAST sustainable. First, output SARIF and let your forge render findings inline in the merge request; a security report nobody opens is dead weight. Second, keep suppressions in the code (// nosemgrep: rule-id — reason) rather than in a central exclusion file, so that a reviewer sees the justification next to the line it protects.
Dependencies, images and the Scaleway Container Registry
Software composition analysis is where you get the highest return per minute of CI. Trivy handles both filesystem scanning (lockfiles, licences) and image scanning, and Grype is a solid alternative. Scan the image after the build but before the push, so a vulnerable artefact never reaches your Scaleway registry namespace at rg.fr-par.scw.cloud.
Two practices matter more than the choice of scanner. Pin base images by digest rather than tag, so a rebuild is reproducible and a scan result stays meaningful. And generate an SBOM at build time, store it as an artefact, and rescan it nightly: a container that was clean on Monday is not clean on Friday, and CVE disclosure does not wait for your next release.
Terraform and IaC scanning against Scaleway resources
Checkov and Trivy's config scanner both understand the Scaleway Terraform provider well enough to catch the classic mistakes: an scaleway_instance_security_group with an inbound rule open to 0.0.0.0/0 on port 22, an object storage bucket left public, a Kapsule pool exposed on a public network when a Private Network would do. Combine that with an IAM policy review: Scaleway's model of applications, groups and policies makes least privilege easy, but the default reflex of granting ProjectManager to a CI application is depressingly common. Give the pipeline application only ContainerRegistryFullAccess and KubernetesFullAccess scoped to the right project, and rotate its API key.
DAST needs a real environment — make it ephemeral
DAST is where most pipelines stop, because it requires a running application. On Scaleway you have two good options. For containerised HTTP services, Serverless Containers can spin up a per-merge-request deployment in seconds and scale to zero afterwards, which keeps the cost of review environments negligible. For anything with stateful dependencies, deploy a namespace per merge request on Kapsule and tear it down on merge.
Then run OWASP ZAP against it. The baseline scan is a passive crawl that takes a couple of minutes and is safe to run on every MR. The full active scan takes far longer and should run nightly against a dedicated staging environment. If your service is an API, use zap-api-scan.py with your OpenAPI specification: it gives ZAP the endpoint inventory it cannot discover by crawling, and dramatically improves coverage. Nuclei is a useful complement for templated checks on exposed infrastructure — misconfigured headers, default panels, known CVEs on the edge.
The hard part of DAST is authentication. Budget time for it: a ZAP context file with a login script and a session token, or a pre-issued JWT injected via a header. Without it, you are scanning your login page and nothing else.
A pipeline you can copy
stages: [secrets, sast, build, review, dast]
variables:
REGISTRY: rg.fr-par.scw.cloud/my-namespace
IMAGE: $REGISTRY/api:$CI_COMMIT_SHORT_SHA
gitleaks:
stage: secrets
image: zricethezav/gitleaks:latest
script: ["gitleaks detect --source . --redact --exit-code 1"]
semgrep:
stage: sast
image: semgrep/semgrep:latest
script:
- semgrep ci --sarif --output semgrep.sarif
artifacts:
reports: { sast: semgrep.sarif }
checkov:
stage: sast
image: bridgecrew/checkov:latest
script:
- checkov -d infra/ --framework terraform --compact --hard-fail-on HIGH
build-and-scan:
stage: build
image: quay.io/buildah/stable
script:
- buildah bud -t $IMAGE .
- trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 $IMAGE
- trivy image --format cyclonedx -o sbom.json $IMAGE
- echo "$SCW_SECRET_KEY" | buildah login -u nologin --password-stdin rg.fr-par.scw.cloud
- buildah push $IMAGE
- cosign sign --key env://COSIGN_KEY $IMAGE
artifacts:
paths: [sbom.json]
deploy-review:
stage: review
script:
- kubectl create ns review-$CI_MERGE_REQUEST_IID --dry-run=client -o yaml | kubectl apply -f -
- helm upgrade --install api ./chart -n review-$CI_MERGE_REQUEST_IID --set image=$IMAGE
environment:
name: review/$CI_MERGE_REQUEST_IID
url: https://mr-$CI_MERGE_REQUEST_IID.review.example.com
on_stop: stop-review
zap-baseline:
stage: dast
image: ghcr.io/zaproxy/zaproxy:stable
script:
- zap-api-scan.py -t $CI_ENVIRONMENT_URL/openapi.json -f openapi -r zap.html -I
artifacts:
paths: [zap.html]
allow_failure: trueThe -I flag and allow_failure: true on the DAST job are deliberate: you observe before you block. Once the baseline is stable and false positives are filtered in a ZAP rules file, flip it to blocking.
Closing the loop at runtime
Scanning stops at deployment; attacks do not. On Kapsule, three controls give disproportionate value. Enable Pod Security Admission in restricted mode on application namespaces, which kills privileged containers and host mounts by default. Apply default-deny NetworkPolicies so that a compromised pod cannot pivot laterally — Kapsule's CNI supports them natively. And ship audit logs and Falco events into Cockpit, where Scaleway already aggregates your metrics and logs into managed Grafana, Loki and Prometheus endpoints.
Complete the picture with Scaleway Secret Manager instead of Kubernetes Secrets in plain etcd, Audit Trail for API-level traceability of who changed what in your project, and short-lived API keys for CI applications. None of this is exotic; the discipline is in doing it consistently.
What actually makes it stick
The technical assembly above takes a few days. Making it survive a year takes three organisational decisions. Define an explicit SLA per severity — critical fixed in days, high in weeks — and track the backlog like any other technical debt. Give teams a documented exception process with an expiry date, otherwise they will invent an undocumented one. And measure the pipeline itself: if the security stages add more than a couple of minutes to a merge request, engineers will find a way around them, and no amount of policy will change that.
DevSecOps on Scaleway is less turnkey than on AWS or GCP, but the result is more portable and easier to audit: every control lives in your repositories, not in a provider console. For teams that chose Scaleway for sovereignty reasons in the first place, that is exactly the right trade-off.
