How to use this lesson
These questions test engineering hygiene at organisational scale:
- measurable quality;
- a trustworthy supply chain;
- secrets that never leak.
Explain the policy (what's enforced, and where), and the mechanism (the tools, and how they plug into the pipeline).
Short answer: The Sonar scanner (a Maven or Gradle plugin, or the CLI) sends the source code, compiled bytecode, and test and coverage reports (JaCoCo XML) to the SonarQube server. Language analysers parse the code into syntax trees and apply rules: data-flow and control-flow analysis, pattern matching, and taint analysis for security (in editions that support it). The key metrics:
- Reliability: bugs (and their rating).
- Security: vulnerabilities, and security hotspots (code to review).
- Maintainability: code smells, technical debt (estimated remediation time), and the debt ratio.
- Coverage: line and branch coverage from the imported reports.
- Duplications: duplicated lines and blocks.
- Size and complexity: lines of code, and cyclomatic and cognitive complexity.
The Quality Gate evaluates conditions, typically on new code ("clean as you code"): coverage ≥ 80%, no new critical issues, duplication below 3%, and all hotspots reviewed. The result is reported back to the PR.
Q2. How do you fail a build when code coverage is too low in Sonar?
Short answer:
- Set a Quality Gate condition, for example "Coverage on New Code < 80% → fail".
- Make the pipeline wait for the gate result:
-Dsonar.qualitygate.wait=true (Maven or Gradle scanner, or the SonarQube Quality Gate GitHub Action). It polls the server, and fails the step if the gate fails.
- Make that check required in branch protection.
Coverage must be imported (sonar.coverage.jacoco.xmlReportPaths), and the tests must run before the scan. Exclude generated code from the coverage (sonar.coverage.exclusions). Alternatively (or as well): JaCoCo's check goal with rules (<minimum>0.80</minimum> on bundle lines or branches) fails the build locally, with no server needed.
Q3. What's the difference between Nexus and Artifactory? Where do you store your artifacts?
Short answer: Both are binary repository managers, which host your artifacts (release and snapshot JARs, Docker images, npm, Helm charts) and proxy and cache public repositories (Maven Central, Docker Hub):
- Sonatype Nexus Repository: popular, with a strong Maven heritage and a free OSS edition. It supports many formats, with component security (Sonatype Lifecycle) in the commercial tiers.
- JFrog Artifactory: a universal repository with very broad format support, strong high availability or replication (multi-site), rich metadata and build info (build-to-artifact traceability), Xray security scanning, and a SaaS offering.
Where artifacts live, in practice:
- libraries and releases in Nexus or Artifactory (release repositories, immutable);
- container images in a registry (ECR, Artifact Registry, ACR, GHCR, Harbor, or Artifactory);
- Helm charts in OCI registries;
- retention policies clean up snapshots and old builds.
Q4. If your artifact storage becomes inaccessible, how does deployment continue?
Short answer:
- Deployments shouldn't depend on building at deploy time: you deploy already-built, immutable images that are already in the registry (and cached on the nodes). Replicate the registry across regions (ECR cross-region replication, Harbor or Artifactory replication), so production pulls from a local replica.
- High availability for the repository manager: an HA cluster, or SaaS, with backups, and replication to a secondary instance that CI can fail over to (configure mirrors, or
settings.xml fallbacks, with care).
- Caching: CI caches of
~/.m2/Gradle, proxy caching of external repositories (so an outage of Maven Central doesn't break builds), and pre-pulled base images on the build agents.
- Kubernetes:
imagePullPolicy: IfNotPresent with digest-pinned images, so the nodes use the cached layers. Keep the previous versions available for rollback.
- Runbooks: monitor the repository's availability, have an emergency procedure to deploy from a secondary registry, and test it.
Q5. How do you handle private artifact repositories in CI/CD?
Short answer:
- Authentication:
- CI injects the credentials from its secret store into
settings.xml (Maven <servers>, through setup-java server-id configuration) or gradle.properties/environment variables;
- prefer short-lived tokens (OIDC federation from GitHub Actions or GitLab to Artifactory or cloud registries), or scoped deploy tokens, over personal passwords.
- One mirror: route all dependency resolution through the internal repository manager (it proxies Central too). That gives security (no dependency confusion), speed (caching) and availability.
- Publishing:
- only CI publishes releases (developers don't);
- release repositories are immutable, with version redeploys prevented;
- signed artifacts (GPG or Sigstore);
- build-info metadata.
- Container registries:
docker login with CI credentials, or workload identity (IRSA/ECR, GKE Workload Identity). Kubernetes pulls through imagePullSecrets, or node IAM roles.
Q6. How do you automate dependency scanning and CVE detection?
Short answer:
- Software composition analysis (SCA) in CI: OWASP Dependency-Check, Snyk, Sonatype Lifecycle, JFrog Xray, GitHub Dependabot alerts or Advanced Security (dependency review on PRs), Trivy or Grype (which also scan JARs inside images).
- Policy: fail PRs or builds on critical or high CVEs with fixes available, with time-boxed exceptions (documented suppressions, like VEX or
suppressions.xml), and licence policy checks.
- Automated updates: Dependabot or Renovate, with grouping, auto-merge for patch updates when the tests pass, and schedules. Spring Boot and BOM upgrades cover whole families of libraries.
- An SBOM for every build (CycloneDX Maven or Gradle plugin, or Syft), stored alongside the artifact, so you can quickly answer "are we affected?" when a new CVE (like Log4Shell) appears. Use continuous monitoring of the deployed SBOMs (Dependency-Track).
- Container base images: rebuild and rescan on base updates.
Q7. What are the security best practices when exposing services in the cloud?
Short answer:
- Minimise exposure:
- only edge components (a load balancer or API gateway) are public;
- services run in private subnets;
- security groups and NACLs, and Kubernetes NetworkPolicies, deny by default.
- TLS everywhere (managed certificates, HSTS), and mTLS internally where feasible.
- Authentication and authorisation at the gateway and in the services (OAuth2/JWT, zero trust).
- WAF (the OWASP rule sets, bot control), DDoS protection (AWS Shield, Cloud Armor), rate limiting.
- Least-privilege IAM: workload identities (IRSA, Workload Identity), with no long-lived access keys, and scoped roles per service.
- Secrets in managed stores, with encryption at rest (KMS), and no public buckets (block public access).
- Logging and detection: CloudTrail or audit logs, flow logs, GuardDuty or Security Command Center, and SIEM alerts.
- Patch and scan: images, dependencies, and IaC scanning (Checkov, tfsec), plus cloud security posture management (CSPM).
- Secure API design: input validation, output encoding, no verbose errors, and CORS allow-lists.
Q8. How is HashiCorp Vault different from AWS Secrets Manager?
Short answer:
-
AWS Secrets Manager:
- a managed, AWS-native secret store, with automatic rotation (Lambda-based, built-in for RDS, Aurora and Redshift);
- IAM-based access control, KMS encryption, CloudTrail auditing;
- cross-region replication;
- pricing per secret and per API call.
It's simple, and ideal for AWS-centric workloads. Parameter Store is its cheaper, simpler sibling.
-
HashiCorp Vault:
- a cloud-agnostic secrets platform (self-managed, or HCP Vault);
- dynamic secrets (on-demand, short-lived database, cloud and SSH credentials, per lease);
- encryption as a service (the Transit engine);
- a PKI (a certificate authority);
- many auth methods (Kubernetes, OIDC, AppRole, cloud IAM) and fine-grained policies;
- namespaces, leases and revocation.
It's powerful for multi-cloud or hybrid environments, but you run it (HA, unsealing, upgrades), or pay for HCP.
-
Spring integration: Spring Cloud Vault, and the Spring Cloud AWS Secrets Manager config import.
Q9. How do you manage secrets, overall? How do you rotate them automatically in production?
Short answer:
- The principles:
- Never in code or Git (scan for them with gitleaks or GitHub secret scanning, including push protection).
- A central secret manager (Vault, cloud secret managers) as the source of truth.
- Least privilege per service identity.
- Short-lived credentials where possible (dynamic secrets, and OIDC federation).
- Rotation.
- Audit.
- Encryption at rest and in transit.
- Break-glass procedures.
- Automatic rotation:
- managed rotation (Secrets Manager rotation Lambdas for RDS; Vault dynamic database credentials, with TTLs and auto-revocation);
- two-phase or dual-secret rotation: create the new credential → deploy or propagate it (both valid) → switch the consumers → revoke the old one, so there's no downtime;
- applications reload without restarts: Spring Cloud Vault lease renewal and rotation, HikariCP picking up new credentials for new connections, or file-mounted secrets with refresh; otherwise, automated rolling restarts;
- rotate the signing keys (JWT JWKS with
kid overlap) and TLS certificates (cert-manager or ACM auto-renewal);
- alert on rotation failures and expiring secrets.
Q10. What are the dangers of using environment variables for secrets?
Short answer: Environment variables are convenient, but leaky:
- They're visible to anything that can inspect the process:
/proc/<pid>/environ, docker inspect, kubectl describe pod (for inline values), and debugging tools.
- They're inherited by child processes (shelling out to tools passes the secrets on).
- They're frequently logged or dumped: crash reports, error pages, "print all config" debugging, Actuator
/env (if not sanitised), and APM agents capturing the environment.
- They're static for the process lifetime: rotation needs restarts.
- In CI, they can leak through verbose build logs.
Safer options:
- mounted secret files (tmpfs, read-only), read at startup or reload;
- fetching directly from the secret manager through SDKs or Spring Cloud integrations, with short-lived credentials;
- if environment variables are used, keep them minimal, mask them in logs and Actuator, and restrict access to the pod specs.
Follow-up questions this topic invites — and their answers
Q: What's the difference between a vulnerability and a security hotspot in SonarQube?
A: A vulnerability is code Sonar is confident is exploitable (it must be fixed). A hotspot is security-sensitive code (crypto usage, a regex, cookie settings) that needs human review, to decide whether it's safe.
Q: How do you avoid alert fatigue from dependency scanners?
A: Gate on severity and fixability, use reachability analysis where available, group updates, auto-merge safe patches, triage with VEX statements, and track mean time to remediate instead of raw counts.
Q: What is Sigstore/cosign?
A: Tools for signing and verifying container images and artifacts (with keyless signing through OIDC identities and a transparency log). Admission controllers can then allow only signed images from trusted pipelines, which protects the supply chain.
Q: Where should the Maven settings.xml credentials live in CI?
A: Generate them at runtime from CI secrets (for example, setup-java with server-id, username and password taken from secrets), never commit them, and prefer short-lived tokens obtained through OIDC.