diff --git a/.gitignore b/.gitignore index 93f9a1d..ec14ecc 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,13 @@ HELP.md *.key .gstack/ .claude/ +# Local env files — CSO finding #2. dotenv pattern предполагает не-committed +# .env с реальными creds для local dev. Без этого правила `git add .` засосёт +# secrets. Whitelist .env.example / .env.template / .env.sample — шаблоны. +.env +.env.local +.env.*.local +*.env +!.env.example +!.env.template +!.env.sample diff --git a/ordinis-app/Dockerfile b/ordinis-app/Dockerfile index 9e06718..165c353 100644 --- a/ordinis-app/Dockerfile +++ b/ordinis-app/Dockerfile @@ -30,7 +30,14 @@ RUN mvn -B -pl ordinis-app -am package -DskipTests \ -Dgit.commit.time="$GIT_TIME" FROM repo.nstart.cloud/library/eclipse-temurin:21-jre +# Non-root user — security hardening (CSO report 2026-05-27 finding #1). +# Eclipse-temurin runtime image не задаёт USER by default → JVM от root. +# Compromise через Spring Boot CVE / Jackson deserialization без USER +# становится root-в-контейнере → escalation surface на ноду. UID 10001 +# не конфликтует с system users (0-999) и distribution-reserved (1000-9999). +RUN groupadd -r -g 10001 app && useradd -r -u 10001 -g app -s /sbin/nologin app WORKDIR /app -COPY --from=build /build/ordinis-app/target/*.jar /app/app.jar +COPY --from=build --chown=app:app /build/ordinis-app/target/*.jar /app/app.jar +USER app EXPOSE 8080 ENTRYPOINT ["java", "-XX:+UseZGC", "-XX:MaxRAMPercentage=75", "-jar", "/app/app.jar"] diff --git a/ordinis-app/src/main/resources/application.yml b/ordinis-app/src/main/resources/application.yml index 330b395..2e68acd 100644 --- a/ordinis-app/src/main/resources/application.yml +++ b/ordinis-app/src/main/resources/application.yml @@ -12,14 +12,21 @@ management: endpoints: web: exposure: - # `conditions`, `beans`, `configprops`, `loggers` — diagnostic четвёрка - # для autoconfig debug (например: почему MailSenderAutoConfiguration - # не fired при наличии SPRING_MAIL_HOST env var и starter-mail на - # classpath). `loggers` runtime-toggle позволяет крутить - # `org.springframework.boot.autoconfigure` в DEBUG без redeploy. - # Endpoints sensitive — exposed только на staging behind cluster-internal - # Ingress (auth.required=true в prod). - include: health,info,prometheus,refresh,metrics,env,mappings,conditions,beans,configprops,loggers + # CSO finding #3 — defense-in-depth. Default exposure narrowed к трём + # безопасным: health (k8s probes), info (UI banner), prometheus + # (ServiceMonitor scrape). Sensitive endpoints (env, configprops, + # beans, mappings, conditions, loggers) выключены by default — + # утечка ORDINIS_KEYCLOAK_ADMIN_CLIENT_SECRET через /actuator/env + # потенциальна на любой pod-to-pod атаке. + # + # Diagnostic четвёрка (conditions/beans/configprops/loggers) + + # debug-set (env/mappings/refresh/metrics) включаются через env + # override `MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE` на staging + # — для autoconfig debug (например: почему + # MailSenderAutoConfiguration не fired при наличии SPRING_MAIL_HOST + # env var). На prod env override не ставим → defense вместе с + # SecurityConfig denyAll на /actuator/{env,beans,...}. + include: ${MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE:health,info,prometheus} base-path: /actuator endpoint: health: diff --git a/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/SecurityConfig.java b/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/SecurityConfig.java index 3e036b3..f2b7bfb 100644 --- a/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/SecurityConfig.java +++ b/ordinis-auth/src/main/java/cloud/nstart/terravault/ordinis/auth/SecurityConfig.java @@ -40,7 +40,35 @@ public class SecurityConfig { .csrf(csrf -> csrf.disable()) .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> { - auth.requestMatchers("/actuator/**").permitAll(); + // Actuator split — CSO finding #3. + // Раньше /actuator/** = permitAll → /actuator/env публично отдавал + // env vars (включая ORDINIS_KEYCLOAK_ADMIN_CLIENT_SECRET) любому + // pod'у в кластере. Сейчас защищены только три безопасных: + // + // - /actuator/health/** — k8s liveness/readiness probes (бессрочно + // open, иначе pod не Ready). + // - /actuator/info — build info (commit, tag) для UI banner. + // - /actuator/prometheus — Prometheus scrape (cluster-internal + // ServiceMonitor; в принципе можно гейтить по network policy, + // но scrape token convention'а не было). + // + // Остальные (env, configprops, beans, mappings, conditions, + // loggers, refresh, metrics) — denyAll. Если оператор хочет + // diagnose в проде — port-forward к pod и `curl localhost:8080` + // (внутри pod нет network policy), либо temporarily exposed + // через kubectl exec. + // + // Defense-in-depth: дополнительно values-prod.yaml ограничивает + // management.endpoints.web.exposure.include = health,info,prometheus + // на уровне Spring → даже если SecurityFilterChain поменяется, + // endpoint'ов просто не существует. + auth.requestMatchers( + "/actuator/health", + "/actuator/health/**", + "/actuator/info", + "/actuator/prometheus" + ).permitAll(); + auth.requestMatchers("/actuator/**").denyAll(); auth.requestMatchers("/error").permitAll(); // Build-info endpoint — открыт без auth: UI polling с update-banner // должен работать ДО login (anonymous landing → "новая версия" diff --git a/ordinis-projection-writer/Dockerfile b/ordinis-projection-writer/Dockerfile index fc15810..d8f50cc 100644 --- a/ordinis-projection-writer/Dockerfile +++ b/ordinis-projection-writer/Dockerfile @@ -7,7 +7,11 @@ COPY . ./ RUN mvn -B -pl ordinis-projection-writer -am package -DskipTests FROM repo.nstart.cloud/library/eclipse-temurin:21-jre +# Non-root user — security hardening (CSO report 2026-05-27 finding #1). +# См. ordinis-app/Dockerfile для rationale. +RUN groupadd -r -g 10001 app && useradd -r -u 10001 -g app -s /sbin/nologin app WORKDIR /app -COPY --from=build /build/ordinis-projection-writer/target/*.jar /app/app.jar +COPY --from=build --chown=app:app /build/ordinis-projection-writer/target/*.jar /app/app.jar +USER app EXPOSE 8082 ENTRYPOINT ["java", "-XX:+UseZGC", "-XX:MaxRAMPercentage=75", "-jar", "/app/app.jar"] diff --git a/ordinis-projection-writer/src/main/resources/application.yml b/ordinis-projection-writer/src/main/resources/application.yml index 39eac18..9c44ab3 100644 --- a/ordinis-projection-writer/src/main/resources/application.yml +++ b/ordinis-projection-writer/src/main/resources/application.yml @@ -14,7 +14,8 @@ management: endpoints: web: exposure: - include: health,info,prometheus,refresh,metrics + # CSO finding #3 — defense-in-depth. См. ordinis-app/application.yml. + include: ${MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE:health,info,prometheus} endpoint: health: probes: diff --git a/ordinis-read-api/Dockerfile b/ordinis-read-api/Dockerfile index 8ae5002..5cfaddd 100644 --- a/ordinis-read-api/Dockerfile +++ b/ordinis-read-api/Dockerfile @@ -7,7 +7,12 @@ COPY . ./ RUN mvn -B -pl ordinis-read-api -am package -DskipTests FROM repo.nstart.cloud/library/eclipse-temurin:21-jre +# Non-root user — security hardening (CSO report 2026-05-27 finding #1). +# См. ordinis-app/Dockerfile для rationale (compromise → root в контейнере +# = escalation surface на ноду). UID 10001 outside system+distro reserved. +RUN groupadd -r -g 10001 app && useradd -r -u 10001 -g app -s /sbin/nologin app WORKDIR /app -COPY --from=build /build/ordinis-read-api/target/*.jar /app/app.jar +COPY --from=build --chown=app:app /build/ordinis-read-api/target/*.jar /app/app.jar +USER app EXPOSE 8081 ENTRYPOINT ["java", "-XX:+UseZGC", "-XX:MaxRAMPercentage=75", "-jar", "/app/app.jar"] diff --git a/ordinis-read-api/src/main/resources/application.yml b/ordinis-read-api/src/main/resources/application.yml index d398a90..4616bfd 100644 --- a/ordinis-read-api/src/main/resources/application.yml +++ b/ordinis-read-api/src/main/resources/application.yml @@ -12,7 +12,9 @@ management: endpoints: web: exposure: - include: health,info,prometheus,refresh,metrics,env,mappings + # CSO finding #3 — defense-in-depth. См. ordinis-app/application.yml + # для rationale (narrow default, env-override для staging diagnostic). + include: ${MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE:health,info,prometheus} endpoint: health: probes: