dockerls 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. dockerls/__init__.py +31 -0
  2. dockerls/application/__init__.py +0 -0
  3. dockerls/application/dto/__init__.py +3 -0
  4. dockerls/application/dto/analysis.py +257 -0
  5. dockerls/application/services/__init__.py +0 -0
  6. dockerls/application/services/alternatives_lookup.py +167 -0
  7. dockerls/application/services/composite_repository.py +106 -0
  8. dockerls/application/services/cross_validation.py +233 -0
  9. dockerls/application/services/ecosystems.py +350 -0
  10. dockerls/application/services/fallback_scanner.py +97 -0
  11. dockerls/application/services/hardening_analysis.py +174 -0
  12. dockerls/application/services/migration.py +297 -0
  13. dockerls/application/services/progress.py +56 -0
  14. dockerls/application/services/remediation.py +321 -0
  15. dockerls/application/services/scan_history_store.py +88 -0
  16. dockerls/application/services/scanner_factory.py +88 -0
  17. dockerls/application/services/source_registry.py +151 -0
  18. dockerls/application/services/tag_history_store.py +76 -0
  19. dockerls/application/services/teardown.py +50 -0
  20. dockerls/application/services/verdict.py +298 -0
  21. dockerls/application/services/version_discovery.py +108 -0
  22. dockerls/application/use_cases/__init__.py +0 -0
  23. dockerls/application/use_cases/analyze_dockerfile.py +103 -0
  24. dockerls/application/use_cases/analyze_image.py +173 -0
  25. dockerls/application/use_cases/build_image.py +1795 -0
  26. dockerls/application/use_cases/compare_images.py +91 -0
  27. dockerls/application/use_cases/fleet_scan.py +240 -0
  28. dockerls/application/use_cases/recommend_images.py +1078 -0
  29. dockerls/application/use_cases/registry_audit.py +133 -0
  30. dockerls/application/use_cases/search_images.py +23 -0
  31. dockerls/application/use_cases/upgrade_base.py +167 -0
  32. dockerls/cache/__init__.py +0 -0
  33. dockerls/cache/sqlite_cache.py +184 -0
  34. dockerls/cli/__init__.py +0 -0
  35. dockerls/cli/analysis_baseline.py +98 -0
  36. dockerls/cli/app.py +294 -0
  37. dockerls/cli/commands/__init__.py +0 -0
  38. dockerls/cli/commands/advisor.py +262 -0
  39. dockerls/cli/commands/alternatives.py +291 -0
  40. dockerls/cli/commands/analyze.py +429 -0
  41. dockerls/cli/commands/analyze_dockerfile.py +104 -0
  42. dockerls/cli/commands/base_cmd.py +244 -0
  43. dockerls/cli/commands/base_image.py +551 -0
  44. dockerls/cli/commands/build.py +1300 -0
  45. dockerls/cli/commands/cache_cmd.py +104 -0
  46. dockerls/cli/commands/compare.py +177 -0
  47. dockerls/cli/commands/controls.py +110 -0
  48. dockerls/cli/commands/doctor.py +566 -0
  49. dockerls/cli/commands/export.py +81 -0
  50. dockerls/cli/commands/fleet.py +159 -0
  51. dockerls/cli/commands/health.py +84 -0
  52. dockerls/cli/commands/login.py +53 -0
  53. dockerls/cli/commands/policy_cmd.py +111 -0
  54. dockerls/cli/commands/provenance_cmd.py +162 -0
  55. dockerls/cli/commands/recommend.py +761 -0
  56. dockerls/cli/commands/registry_audit_cmd.py +103 -0
  57. dockerls/cli/commands/sbom.py +144 -0
  58. dockerls/cli/commands/search.py +86 -0
  59. dockerls/cli/commands/verify.py +115 -0
  60. dockerls/cli/commands/version.py +12 -0
  61. dockerls/cli/commands/vex_cmd.py +117 -0
  62. dockerls/cli/dependencies.py +530 -0
  63. dockerls/cli/image_names.py +79 -0
  64. dockerls/cli/options.py +42 -0
  65. dockerls/cli/progress.py +145 -0
  66. dockerls/cli/publish_prompt.py +123 -0
  67. dockerls/cli/rendering.py +214 -0
  68. dockerls/cli/runtime.py +65 -0
  69. dockerls/cli/scan_failure.py +71 -0
  70. dockerls/cli/text.py +39 -0
  71. dockerls/cli/validators.py +35 -0
  72. dockerls/cli/vulnerability_view.py +154 -0
  73. dockerls/domain/__init__.py +0 -0
  74. dockerls/domain/entities/__init__.py +75 -0
  75. dockerls/domain/entities/declared_metadata.py +147 -0
  76. dockerls/domain/entities/dockerfile_analysis.py +318 -0
  77. dockerls/domain/entities/image.py +109 -0
  78. dockerls/domain/entities/image_facts.py +137 -0
  79. dockerls/domain/entities/recommendation.py +33 -0
  80. dockerls/domain/entities/scan_result.py +129 -0
  81. dockerls/domain/entities/vulnerability.py +232 -0
  82. dockerls/domain/interfaces/__init__.py +17 -0
  83. dockerls/domain/interfaces/cache_store.py +18 -0
  84. dockerls/domain/interfaces/dockerfile_validator.py +99 -0
  85. dockerls/domain/interfaces/eol_checker.py +11 -0
  86. dockerls/domain/interfaces/image_repository.py +15 -0
  87. dockerls/domain/interfaces/scanner.py +15 -0
  88. dockerls/domain/security_controls.py +362 -0
  89. dockerls/domain/value_objects/__init__.py +49 -0
  90. dockerls/domain/value_objects/attack_surface.py +198 -0
  91. dockerls/domain/value_objects/base_recipe.py +600 -0
  92. dockerls/domain/value_objects/base_upgrade.py +292 -0
  93. dockerls/domain/value_objects/build_labels.py +99 -0
  94. dockerls/domain/value_objects/build_policy.py +412 -0
  95. dockerls/domain/value_objects/confidence.py +156 -0
  96. dockerls/domain/value_objects/fleet.py +174 -0
  97. dockerls/domain/value_objects/gate.py +327 -0
  98. dockerls/domain/value_objects/hardening.py +303 -0
  99. dockerls/domain/value_objects/image_reference.py +90 -0
  100. dockerls/domain/value_objects/inheritance.py +352 -0
  101. dockerls/domain/value_objects/network_policy.py +280 -0
  102. dockerls/domain/value_objects/production_readiness.py +145 -0
  103. dockerls/domain/value_objects/provenance.py +211 -0
  104. dockerls/domain/value_objects/recipe_diff.py +188 -0
  105. dockerls/domain/value_objects/registry_audit.py +195 -0
  106. dockerls/domain/value_objects/registry_target.py +225 -0
  107. dockerls/domain/value_objects/remediation_score.py +62 -0
  108. dockerls/domain/value_objects/scan_history.py +183 -0
  109. dockerls/domain/value_objects/scan_plan.py +193 -0
  110. dockerls/domain/value_objects/scanner_db.py +143 -0
  111. dockerls/domain/value_objects/security_score.py +160 -0
  112. dockerls/domain/value_objects/security_tier.py +122 -0
  113. dockerls/domain/value_objects/tag_history.py +180 -0
  114. dockerls/domain/value_objects/tool_release.py +253 -0
  115. dockerls/domain/value_objects/tristate.py +47 -0
  116. dockerls/domain/value_objects/vex.py +249 -0
  117. dockerls/exit_codes.py +23 -0
  118. dockerls/exporters/__init__.py +0 -0
  119. dockerls/exporters/base.py +17 -0
  120. dockerls/exporters/csv_exporter.py +85 -0
  121. dockerls/exporters/factory.py +31 -0
  122. dockerls/exporters/html_exporter.py +105 -0
  123. dockerls/exporters/json_exporter.py +19 -0
  124. dockerls/exporters/markdown_exporter.py +84 -0
  125. dockerls/exporters/sarif_exporter.py +245 -0
  126. dockerls/infrastructure/__init__.py +0 -0
  127. dockerls/infrastructure/config/__init__.py +0 -0
  128. dockerls/infrastructure/config/policy_file.py +165 -0
  129. dockerls/infrastructure/config/settings.py +197 -0
  130. dockerls/infrastructure/database/__init__.py +0 -0
  131. dockerls/infrastructure/database/models.py +78 -0
  132. dockerls/infrastructure/dockerfile_validator.py +1899 -0
  133. dockerls/infrastructure/evidence.py +99 -0
  134. dockerls/infrastructure/hashing.py +165 -0
  135. dockerls/infrastructure/logging/__init__.py +0 -0
  136. dockerls/infrastructure/logging/setup.py +98 -0
  137. dockerls/infrastructure/network/__init__.py +0 -0
  138. dockerls/infrastructure/network/guarded_client.py +107 -0
  139. dockerls/infrastructure/network/host_guard.py +117 -0
  140. dockerls/infrastructure/redaction.py +135 -0
  141. dockerls/infrastructure/templates/hardening/alpine.dockerfile +44 -0
  142. dockerls/infrastructure/templates/hardening/debian.dockerfile +45 -0
  143. dockerls/infrastructure/templates/hardening/distroless.dockerfile +34 -0
  144. dockerls/infrastructure/templates/hardening/go-alpine.dockerfile +52 -0
  145. dockerls/infrastructure/templates/hardening/go-debian.dockerfile +54 -0
  146. dockerls/infrastructure/templates/hardening/go-distroless.dockerfile +43 -0
  147. dockerls/infrastructure/templates/hardening/go-scratch.dockerfile +48 -0
  148. dockerls/infrastructure/templates/hardening/go.dockerfile +50 -0
  149. dockerls/infrastructure/templates/hardening/gradle-alpine.dockerfile +51 -0
  150. dockerls/infrastructure/templates/hardening/gradle.dockerfile +52 -0
  151. dockerls/infrastructure/templates/hardening/java-alpine.dockerfile +50 -0
  152. dockerls/infrastructure/templates/hardening/java-debian.dockerfile +50 -0
  153. dockerls/infrastructure/templates/hardening/java-distroless.dockerfile +39 -0
  154. dockerls/infrastructure/templates/hardening/java-ubuntu.dockerfile +54 -0
  155. dockerls/infrastructure/templates/hardening/java.dockerfile +60 -0
  156. dockerls/infrastructure/templates/hardening/maven-alpine.dockerfile +56 -0
  157. dockerls/infrastructure/templates/hardening/maven.dockerfile +57 -0
  158. dockerls/infrastructure/templates/hardening/node-alpine.dockerfile +47 -0
  159. dockerls/infrastructure/templates/hardening/node-debian.dockerfile +54 -0
  160. dockerls/infrastructure/templates/hardening/node-distroless.dockerfile +46 -0
  161. dockerls/infrastructure/templates/hardening/node-ubuntu.dockerfile +63 -0
  162. dockerls/infrastructure/templates/hardening/node.dockerfile +61 -0
  163. dockerls/infrastructure/templates/hardening/php-alpine.dockerfile +45 -0
  164. dockerls/infrastructure/templates/hardening/php-debian.dockerfile +45 -0
  165. dockerls/infrastructure/templates/hardening/php-ubuntu.dockerfile +49 -0
  166. dockerls/infrastructure/templates/hardening/php.dockerfile +44 -0
  167. dockerls/infrastructure/templates/hardening/python-alpine.dockerfile +51 -0
  168. dockerls/infrastructure/templates/hardening/python-debian.dockerfile +54 -0
  169. dockerls/infrastructure/templates/hardening/python-distroless.dockerfile +51 -0
  170. dockerls/infrastructure/templates/hardening/python-ubuntu.dockerfile +60 -0
  171. dockerls/infrastructure/templates/hardening/python.dockerfile +58 -0
  172. dockerls/infrastructure/templates/hardening/ruby-alpine.dockerfile +48 -0
  173. dockerls/infrastructure/templates/hardening/ruby-debian.dockerfile +50 -0
  174. dockerls/infrastructure/templates/hardening/rust-alpine.dockerfile +50 -0
  175. dockerls/infrastructure/templates/hardening/rust-debian.dockerfile +48 -0
  176. dockerls/infrastructure/templates/hardening/rust-scratch.dockerfile +44 -0
  177. dockerls/infrastructure/templates/hardening/rust.dockerfile +54 -0
  178. dockerls/infrastructure/templates/hardening/ubuntu.dockerfile +49 -0
  179. dockerls/infrastructure/toolchain/__init__.py +0 -0
  180. dockerls/infrastructure/toolchain/db_metadata.py +115 -0
  181. dockerls/infrastructure/toolchain/installer.py +435 -0
  182. dockerls/integrations/__init__.py +0 -0
  183. dockerls/integrations/dhi/__init__.py +0 -0
  184. dockerls/integrations/dhi/catalog.py +457 -0
  185. dockerls/integrations/dhi/definition.py +151 -0
  186. dockerls/integrations/dhi/repository.py +238 -0
  187. dockerls/integrations/dockerhub/__init__.py +0 -0
  188. dockerls/integrations/dockerhub/client.py +318 -0
  189. dockerls/integrations/dockerhub/urls.py +75 -0
  190. dockerls/integrations/endoflife/__init__.py +0 -0
  191. dockerls/integrations/endoflife/checker.py +216 -0
  192. dockerls/integrations/engine/__init__.py +0 -0
  193. dockerls/integrations/engine/batch.py +197 -0
  194. dockerls/integrations/engine/client.py +330 -0
  195. dockerls/integrations/engine/locator.py +96 -0
  196. dockerls/integrations/exploitdb/__init__.py +0 -0
  197. dockerls/integrations/exploitdb/client.py +271 -0
  198. dockerls/integrations/grype/__init__.py +0 -0
  199. dockerls/integrations/grype/scanner.py +336 -0
  200. dockerls/integrations/registry/__init__.py +0 -0
  201. dockerls/integrations/registry/hardened.py +284 -0
  202. dockerls/integrations/registry/inspector.py +420 -0
  203. dockerls/integrations/registry/oci.py +259 -0
  204. dockerls/integrations/registry/private.py +79 -0
  205. dockerls/integrations/registry/urls.py +36 -0
  206. dockerls/integrations/scan_errors.py +67 -0
  207. dockerls/integrations/scan_target.py +57 -0
  208. dockerls/integrations/signing/__init__.py +0 -0
  209. dockerls/integrations/signing/cosign.py +484 -0
  210. dockerls/integrations/threat_intel/__init__.py +0 -0
  211. dockerls/integrations/threat_intel/client.py +290 -0
  212. dockerls/integrations/trivy/__init__.py +0 -0
  213. dockerls/integrations/trivy/cache_pool.py +176 -0
  214. dockerls/integrations/trivy/scanner.py +447 -0
  215. dockerls/utils/__init__.py +0 -0
  216. dockerls/utils/auth.py +108 -0
  217. dockerls/utils/executables.py +39 -0
  218. dockerls/utils/ignore_file.py +130 -0
  219. dockerls/utils/rate_limit.py +130 -0
  220. dockerls/utils/resources.py +183 -0
  221. dockerls/utils/retry.py +31 -0
  222. dockerls/utils/safe_yaml.py +166 -0
  223. dockerls/utils/subprocess_runner.py +216 -0
  224. dockerls/utils/validation.py +72 -0
  225. dockerls-1.0.0.dist-info/METADATA +563 -0
  226. dockerls-1.0.0.dist-info/RECORD +230 -0
  227. dockerls-1.0.0.dist-info/WHEEL +5 -0
  228. dockerls-1.0.0.dist-info/entry_points.txt +2 -0
  229. dockerls-1.0.0.dist-info/licenses/LICENSE +21 -0
  230. dockerls-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,135 @@
1
+ r"""One redactor, used everywhere text leaves this process.
2
+
3
+ Credentials reach this tool through several doors: a registry token in a
4
+ `WWW-Authenticate` exchange, a Docker Hub PAT in an exception message, a
5
+ `user:password` embedded in a URL someone put in a config file, an
6
+ `Authorization` header echoed back by a scanner that failed. They then leave
7
+ through several more: the log file, the raw scan artifacts kept as evidence,
8
+ and anything a user attaches to a ticket.
9
+
10
+ Having the masking live inside the logging sink covered exactly one of those
11
+ doors. This module is the shared implementation; the log filter and the
12
+ evidence store both call it, so a pattern added here protects every path at
13
+ once.
14
+
15
+ Three rules shape the patterns:
16
+
17
+ * **Only the key and its separator survive.** `token=` stays so the line
18
+ remains readable; no part of the value does.
19
+ * **Over-masking is the acceptable failure.** A redacted benign string costs
20
+ a moment of confusion. A leaked token costs a credential rotation, and
21
+ the leak is discovered later, by someone else.
22
+ * **The keyword comes first.** Every key pattern begins with the literal
23
+ alternation rather than with `[\w.-]*`, so the engine can scan for a
24
+ literal instead of trying every split of an unbounded character class at
25
+ every position. This is not a micro-optimisation: with the leading star,
26
+ redacting one 2 MB scan artifact took **19 seconds** of pure CPU --
27
+ catastrophic backtracking over the long runs of word characters in a
28
+ vulnerability description. Once per scanned image, that is the whole
29
+ run's budget spent on masking. Keyword-first is 176x faster and masks
30
+ exactly the same strings; the text before the keyword is simply left
31
+ outside the match instead of being consumed and re-emitted.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import re
37
+
38
+ #: What replaces a redacted value. Recognisable on sight, and distinct from
39
+ #: anything a real credential looks like. The exact string is part of the
40
+ #: observable contract -- it appears in every log file this tool has ever
41
+ #: written -- so it is carried over verbatim rather than modernised.
42
+ MASK = "***MASKED***"
43
+
44
+ # The credential-introducing keywords, as a bare literal alternation. It is
45
+ # deliberately *not* wrapped in `[\w.-]*` on both sides: see the module
46
+ # docstring for what that cost. Surrounding word characters are matched
47
+ # after the keyword, where they are bounded by the word itself.
48
+ _SENSITIVE_KEYWORD = r"(?:token|password|passwd|senha|secret|api[-_]?key|credential|auth)"
49
+ #: A key, from its keyword to the end of the identifier: `token`,
50
+ #: `api_key`, and the tail of `x_api_key` (the `x_` is left outside the
51
+ #: match and survives untouched, which renders identically).
52
+ _SENSITIVE_KEY_PATTERN = _SENSITIVE_KEYWORD + r"[\w.-]*"
53
+
54
+ # A quoted key/value pair, as it appears in JSON or a dict repr:
55
+ # "token": "value" 'apiKey' : 'value' "auth": {"token": "value"}
56
+ # The quote between the key and the separator is exactly what the previous
57
+ # pattern could not cross, which left every JSON-shaped log line in clear.
58
+ # The value is matched possessively: when no closing quote follows, the
59
+ # match fails at once instead of backtracking through every prefix of a
60
+ # multi-kilobyte string.
61
+ _QUOTED_KV = re.compile(
62
+ rf"""(?P<prefix>{_SENSITIVE_KEY_PATTERN}["']?\s*[:=]\s*)"""
63
+ rf"""(?P<quote>["'])(?P<value>(?:[^"'\\]|\\.)*+)(?P=quote)""",
64
+ re.IGNORECASE,
65
+ )
66
+
67
+ # An unquoted key/value pair: token=abc, senha: abc, x-api-key: abc.
68
+ _BARE_KV = re.compile(
69
+ rf"(?P<prefix>{_SENSITIVE_KEY_PATTERN}\s*[=:]\s*)(?P<value>[^\s,;&\"'}}\]]+)", re.IGNORECASE
70
+ )
71
+
72
+ # Authorization schemes.
73
+ _SCHEME = re.compile(
74
+ r"\b(?P<scheme>Bearer|Basic|Token|Digest)\s+(?P<value>[^\s,;\"'=:][^\s,;\"']*)",
75
+ re.IGNORECASE,
76
+ )
77
+
78
+ # Credentials embedded in a URL: https://user:secret@host
79
+ _URL_USERINFO = re.compile(r"(?P<prefix>://[^/\s:@]+:)(?P<value>[^@/\s]+)(?P<at>@)")
80
+
81
+ # curl-style inline credentials: -u user:secret, --user user:secret
82
+ _CURL_USER = re.compile(r"(?P<prefix>(?:-u|--user)\s+[^\s:]+:)(?P<value>\S+)")
83
+
84
+ # Credential formats that are self-identifying, so they are redacted even
85
+ # when they appear with no key to introduce them -- a bare token inside a
86
+ # list or an exception message has no "token=" in front of it.
87
+ _KNOWN_SECRET_VALUE = re.compile(
88
+ r"""
89
+ \bdckr_pat_[A-Za-z0-9_-]{8,} # Docker Hub PAT
90
+ | \bgh[pousr]_[A-Za-z0-9]{20,} # GitHub classic token
91
+ | \bgithub_pat_[A-Za-z0-9_]{20,} # GitHub fine-grained PAT
92
+ | \beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]+ # JWT
93
+ | \bAKIA[0-9A-Z]{16}\b # AWS access key id
94
+ | \bxox[baprs]-[A-Za-z0-9-]{10,} # Slack token
95
+ """,
96
+ re.VERBOSE,
97
+ )
98
+
99
+ # multipart/form-data, where the value sits on its own line after a blank
100
+ # line rather than next to the key.
101
+ _MULTIPART = re.compile(
102
+ rf"""(?P<prefix>name=["'][\w.-]{{0,32}}{_SENSITIVE_KEY_PATTERN}["'][^\n]*\r?\n\r?\n)(?P<value>[^\r\n]+)""",
103
+ re.IGNORECASE,
104
+ )
105
+
106
+ _FILE_FORMAT = "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}"
107
+ _CONSOLE_FORMAT = (
108
+ "<level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan> - {message}"
109
+ )
110
+
111
+
112
+ def redact(message: str) -> str:
113
+ """Redact credentials from a log line in every shape they arrive in.
114
+
115
+ Only the key name and separator (e.g. `token=`) are kept, never any part
116
+ of the value. Over-masking a benign line is an acceptable cost; leaking
117
+ a token into a log file is not, so the key patterns are deliberately
118
+ broad.
119
+
120
+ Order matters: scheme patterns run before the key/value ones, because
121
+ in `auth: Bearer <token>` a key/value match would consume only the word
122
+ `Bearer` and stop, leaving the credential in the clear.
123
+ """
124
+ result = _SCHEME.sub(lambda m: f"{m.group('scheme')} {MASK}", message)
125
+ result = _URL_USERINFO.sub(lambda m: f"{m.group('prefix')}{MASK}{m.group('at')}", result)
126
+ result = _CURL_USER.sub(lambda m: f"{m.group('prefix')}{MASK}", result)
127
+ result = _MULTIPART.sub(lambda m: f"{m.group('prefix')}{MASK}", result)
128
+ result = _QUOTED_KV.sub(
129
+ lambda m: f"{m.group('prefix')}{m.group('quote')}{MASK}{m.group('quote')}", result
130
+ )
131
+ result = _BARE_KV.sub(lambda m: f"{m.group('prefix')}{MASK}", result)
132
+ # Last: catch self-identifying credential formats that appeared with no
133
+ # key in front of them for any of the patterns above to anchor on.
134
+ result = _KNOWN_SECRET_VALUE.sub(MASK, result)
135
+ return result
@@ -0,0 +1,44 @@
1
+ # Dockerfile.hardened.alpine
2
+ # Hardened template for Alpine Linux - Minimal Base Container
3
+
4
+ ARG BASE_VERSION=3.20
5
+
6
+ # Stage 1: Build / Setup
7
+ FROM alpine:${BASE_VERSION} AS builder
8
+
9
+ RUN apk update && apk upgrade --no-cache \
10
+ && apk add --no-cache ca-certificates tzdata \
11
+ && rm -rf /var/cache/apk/*
12
+
13
+ # Stage 2: Runtime
14
+ FROM alpine:${BASE_VERSION}
15
+
16
+ LABEL security.scanner="dockerls"
17
+ LABEL security.hardened="true"
18
+ LABEL maintainer="security@company.com"
19
+ LABEL security.cve-contact="security@company.com"
20
+
21
+ # Update security packages and create a dedicated non-root user (UID 10001)
22
+ RUN apk update && apk upgrade --no-cache \
23
+ && apk add --no-cache ca-certificates tzdata \
24
+ && addgroup -g 10001 appgroup \
25
+ && adduser -u 10001 -G appgroup -s /sbin/nologin -D appuser \
26
+ && rm -rf /var/cache/apk/*
27
+
28
+ WORKDIR /app
29
+
30
+ # Copy application files with proper ownership
31
+ COPY --chown=appuser:appgroup . .
32
+
33
+ ARG GIT_SHA=unknown
34
+ ARG BUILD_TIME=unknown
35
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
36
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
37
+
38
+ USER appuser
39
+
40
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
41
+ CMD [ -f /app/health.ok ] || exit 0
42
+
43
+ ENTRYPOINT ["sh", "-c"]
44
+ CMD ["echo 'DockerLs Alpine container ready'"]
@@ -0,0 +1,45 @@
1
+ # Dockerfile.hardened.debian
2
+ # Hardened template for Debian GNU/Linux (Bookworm Slim)
3
+
4
+ ARG DEBIAN_VERSION=bookworm-slim
5
+
6
+ # Stage 1: Build / Setup
7
+ FROM debian:${DEBIAN_VERSION} AS builder
8
+
9
+ RUN apt-get update \
10
+ && apt-get upgrade -y \
11
+ && apt-get install -y --no-install-recommends ca-certificates tzdata \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ # Stage 2: Runtime
15
+ FROM debian:${DEBIAN_VERSION}
16
+
17
+ LABEL security.scanner="dockerls"
18
+ LABEL security.hardened="true"
19
+ LABEL maintainer="security@company.com"
20
+ LABEL security.cve-contact="security@company.com"
21
+
22
+ # Update OS packages and create a non-root user (UID 10001)
23
+ RUN apt-get update \
24
+ && apt-get upgrade -y \
25
+ && apt-get install -y --no-install-recommends ca-certificates tzdata \
26
+ && groupadd -g 10001 appgroup \
27
+ && useradd -u 10001 -g appgroup -s /usr/sbin/nologin -m appuser \
28
+ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
29
+
30
+ WORKDIR /app
31
+
32
+ COPY --chown=appuser:appgroup . .
33
+
34
+ ARG GIT_SHA=unknown
35
+ ARG BUILD_TIME=unknown
36
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
37
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
38
+
39
+ USER appuser
40
+
41
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
42
+ CMD [ -f /app/health.ok ] || exit 0
43
+
44
+ ENTRYPOINT ["sh", "-c"]
45
+ CMD ["echo 'DockerLs Debian container ready'"]
@@ -0,0 +1,34 @@
1
+ # Dockerfile.hardened.distroless
2
+ # Hardened template for Google Distroless (Debian 12 base)
3
+
4
+ ARG BUILDER_VERSION=3.20
5
+
6
+ # Stage 1: Builder
7
+ FROM alpine:${BUILDER_VERSION} AS builder
8
+
9
+ RUN apk update && apk add --no-cache ca-certificates tzdata
10
+
11
+ WORKDIR /app
12
+ COPY . .
13
+
14
+ # Stage 2: Distroless Runtime
15
+ FROM gcr.io/distroless/base-debian12:nonroot
16
+
17
+ LABEL security.scanner="dockerls"
18
+ LABEL security.hardened="true"
19
+ LABEL maintainer="security@company.com"
20
+ LABEL security.cve-contact="security@company.com"
21
+
22
+ WORKDIR /app
23
+
24
+ COPY --from=builder /app /app
25
+
26
+ ARG GIT_SHA=unknown
27
+ ARG BUILD_TIME=unknown
28
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
29
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
30
+
31
+ # nonroot user in Distroless is 65532:65532
32
+ USER 65532:65532
33
+
34
+ ENTRYPOINT ["/app/binary"]
@@ -0,0 +1,52 @@
1
+ # Dockerfile.hardened.go-alpine
2
+ # Hardened template for Go (Alpine Linux)
3
+
4
+ ARG GO_VERSION=1.23-alpine
5
+ ARG ALPINE_VERSION=3.20
6
+
7
+ # Stage 1: Builder
8
+ FROM golang:${GO_VERSION} AS builder
9
+
10
+ RUN apk update && apk add --no-cache git ca-certificates tzdata
11
+
12
+ WORKDIR /app
13
+
14
+ COPY go.mod go.sum ./
15
+ RUN go mod download
16
+
17
+ COPY . .
18
+
19
+ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
20
+ go build -trimpath -ldflags="-s -w" -o /app/binary .
21
+
22
+ # Stage 2: Alpine Runtime
23
+ FROM alpine:${ALPINE_VERSION}
24
+
25
+ LABEL security.scanner="dockerls"
26
+ LABEL security.hardened="true"
27
+ LABEL maintainer="security@company.com"
28
+ LABEL security.cve-contact="security@company.com"
29
+
30
+ RUN apk update && apk upgrade --no-cache \
31
+ && apk add --no-cache ca-certificates tzdata \
32
+ && addgroup -g 10001 appgroup \
33
+ && adduser -u 10001 -G appgroup -s /sbin/nologin -D appuser \
34
+ && rm -rf /var/cache/apk/*
35
+
36
+ WORKDIR /app
37
+
38
+ COPY --from=builder /app/binary /app/binary
39
+
40
+ ARG GIT_SHA=unknown
41
+ ARG BUILD_TIME=unknown
42
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
43
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
44
+
45
+ USER appuser
46
+
47
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
48
+ CMD [ -f /app/binary ] || exit 1
49
+
50
+ EXPOSE 8080
51
+
52
+ ENTRYPOINT ["/app/binary"]
@@ -0,0 +1,54 @@
1
+ # Dockerfile.hardened.go-debian
2
+ # Hardened template for Go (Debian Bookworm Slim)
3
+
4
+ ARG GO_VERSION=1.23-bookworm
5
+ ARG DEBIAN_VERSION=bookworm-slim
6
+
7
+ # Stage 1: Builder
8
+ FROM golang:${GO_VERSION} AS builder
9
+
10
+ RUN apt-get update && apt-get install -y --no-install-recommends \
11
+ git ca-certificates tzdata \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ WORKDIR /app
15
+
16
+ COPY go.mod go.sum ./
17
+ RUN go mod download
18
+
19
+ COPY . .
20
+
21
+ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
22
+ go build -trimpath -ldflags="-s -w" -o /app/binary .
23
+
24
+ # Stage 2: Debian Runtime
25
+ FROM debian:${DEBIAN_VERSION}
26
+
27
+ LABEL security.scanner="dockerls"
28
+ LABEL security.hardened="true"
29
+ LABEL maintainer="security@company.com"
30
+ LABEL security.cve-contact="security@company.com"
31
+
32
+ RUN apt-get update && apt-get upgrade -y \
33
+ && apt-get install -y --no-install-recommends ca-certificates tzdata \
34
+ && groupadd -g 10001 appgroup \
35
+ && useradd -u 10001 -g appgroup -s /usr/sbin/nologin -m appuser \
36
+ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
37
+
38
+ WORKDIR /app
39
+
40
+ COPY --from=builder /app/binary /app/binary
41
+
42
+ ARG GIT_SHA=unknown
43
+ ARG BUILD_TIME=unknown
44
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
45
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
46
+
47
+ USER appuser
48
+
49
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
50
+ CMD [ -f /app/binary ] || exit 1
51
+
52
+ EXPOSE 8080
53
+
54
+ ENTRYPOINT ["/app/binary"]
@@ -0,0 +1,43 @@
1
+ # Dockerfile.hardened.go-distroless
2
+ # Hardened template for Go (Google Distroless Static)
3
+
4
+ ARG GO_VERSION=1.23-alpine
5
+
6
+ # Stage 1: Builder
7
+ FROM golang:${GO_VERSION} AS builder
8
+
9
+ RUN apk update && apk add --no-cache git ca-certificates tzdata
10
+
11
+ WORKDIR /app
12
+
13
+ COPY go.mod go.sum ./
14
+ RUN go mod download
15
+
16
+ COPY . .
17
+
18
+ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
19
+ go build -trimpath -ldflags="-s -w" -o /app/binary .
20
+
21
+ # Stage 2: Distroless Static Runtime
22
+ FROM gcr.io/distroless/static-debian12:nonroot
23
+
24
+ LABEL security.scanner="dockerls"
25
+ LABEL security.hardened="true"
26
+ LABEL maintainer="security@company.com"
27
+ LABEL security.cve-contact="security@company.com"
28
+
29
+ WORKDIR /app
30
+
31
+ COPY --from=builder /app/binary /app/binary
32
+
33
+ ARG GIT_SHA=unknown
34
+ ARG BUILD_TIME=unknown
35
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
36
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
37
+
38
+ # nonroot user in Distroless
39
+ USER 65532:65532
40
+
41
+ EXPOSE 8080
42
+
43
+ ENTRYPOINT ["/app/binary"]
@@ -0,0 +1,48 @@
1
+ # Dockerfile.hardened.go-scratch
2
+ # Hardened template for Go (Scratch - Zero OS CVEs)
3
+
4
+ ARG GO_VERSION=1.23-alpine
5
+
6
+ # Stage 1: Builder
7
+ FROM golang:${GO_VERSION} AS builder
8
+
9
+ RUN apk update && apk add --no-cache git ca-certificates tzdata \
10
+ && update-ca-certificates
11
+
12
+ WORKDIR /app
13
+
14
+ COPY go.mod go.sum ./
15
+ RUN go mod download
16
+
17
+ COPY . .
18
+
19
+ # Secure static compilation (no CGO)
20
+ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
21
+ go build -trimpath -ldflags="-s -w" -o /app/binary .
22
+
23
+ # Stage 2: Scratch Runtime
24
+ FROM scratch
25
+
26
+ LABEL security.scanner="dockerls"
27
+ LABEL security.hardened="true"
28
+ LABEL maintainer="security@company.com"
29
+ LABEL security.cve-contact="security@company.com"
30
+
31
+ # Import TLS certificates and timezone data from the builder
32
+ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
33
+ COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
34
+
35
+ # Copy only the static binary
36
+ COPY --from=builder /app/binary /app/binary
37
+
38
+ ARG GIT_SHA=unknown
39
+ ARG BUILD_TIME=unknown
40
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
41
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
42
+
43
+ # nobody user (UID 65534:65534)
44
+ USER 65534:65534
45
+
46
+ EXPOSE 8080
47
+
48
+ ENTRYPOINT ["/app/binary"]
@@ -0,0 +1,50 @@
1
+ # Dockerfile.hardened.go
2
+ # Hardened template for Go - Minimal Production Ready
3
+
4
+ FROM golang:1.23-alpine AS builder
5
+
6
+ WORKDIR /app
7
+
8
+ # Install CA certificates and git
9
+ RUN apk add --no-cache ca-certificates git && update-ca-certificates && rm -rf /var/cache/apk/*
10
+
11
+ COPY go.mod go.sum* ./
12
+ RUN go mod download || true
13
+
14
+ COPY . .
15
+
16
+ # Static build with CGO disabled and stripping flags
17
+ RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o app .
18
+
19
+ # Stage 2: Runtime minimal (scratch)
20
+ FROM scratch
21
+
22
+ LABEL security.scanner="dockerls"
23
+ LABEL security.hardened="true"
24
+ LABEL maintainer="your-team@company.com"
25
+ LABEL security.cve-contact="security@company.com"
26
+
27
+ # Build metadata
28
+ ARG GIT_SHA=unknown
29
+ ARG BUILD_TIME=unknown
30
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
31
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
32
+
33
+ # Copy SSL root certificates for HTTPS calls
34
+ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
35
+
36
+ # Copy only the static binary
37
+ COPY --from=builder /app/app /app
38
+
39
+ # Expose default port
40
+ EXPOSE 8080
41
+
42
+ # Numeric non-root user (nobody) for scratch
43
+ USER 65534:65534
44
+
45
+ # Secure health check in exec form
46
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
47
+ CMD ["/app", "-health"]
48
+
49
+ # No shell - exec form only
50
+ ENTRYPOINT ["/app"]
@@ -0,0 +1,51 @@
1
+ # Dockerfile.hardened.gradle-alpine
2
+ # Hardened template for a Java application built with Gradle (Alpine).
3
+ #
4
+ # Same separation as the Maven template: the official Gradle image builds,
5
+ # and the runtime carries only the JRE. The Gradle daemon is disabled during
6
+ # the build -- inside a container it is never reused across runs, so keeping
7
+ # it running only wastes memory.
8
+
9
+ ARG GRADLE_VERSION=8-jdk21-alpine
10
+ ARG JRE_VERSION=21-jre-alpine
11
+
12
+ # Stage 1: Build
13
+ FROM gradle:${GRADLE_VERSION} AS builder
14
+
15
+ WORKDIR /app
16
+
17
+ COPY --chown=gradle:gradle build.gradle* settings.gradle* ./
18
+ COPY --chown=gradle:gradle src ./src
19
+ RUN gradle --no-daemon clean build -x test
20
+
21
+ # Stage 2: Runtime
22
+ FROM eclipse-temurin:${JRE_VERSION}
23
+
24
+ LABEL security.scanner="dockerls"
25
+ LABEL security.hardened="true"
26
+ LABEL maintainer="security@company.com"
27
+ LABEL security.cve-contact="security@company.com"
28
+
29
+ ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
30
+
31
+ RUN apk upgrade --no-cache \
32
+ && addgroup -g 10001 appgroup \
33
+ && adduser -u 10001 -G appgroup -s /sbin/nologin -D appuser
34
+
35
+ WORKDIR /app
36
+
37
+ COPY --from=builder --chown=appuser:appgroup /app/build/libs/*.jar /app/app.jar
38
+
39
+ ARG GIT_SHA=unknown
40
+ ARG BUILD_TIME=unknown
41
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
42
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
43
+
44
+ USER appuser
45
+
46
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
47
+ CMD [ -f /app/app.jar ] || exit 1
48
+
49
+ EXPOSE 8080
50
+
51
+ ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -jar /app/app.jar"]
@@ -0,0 +1,52 @@
1
+ # Dockerfile.hardened.gradle
2
+ # Hardened template for a Java application built with Gradle (Debian slim).
3
+ #
4
+ # Same separation as the Maven template: the official Gradle image builds,
5
+ # and the runtime carries only the JRE. The Gradle daemon is disabled during
6
+ # the build -- inside a container it is never reused across runs, so keeping
7
+ # it running only wastes memory.
8
+
9
+ ARG GRADLE_VERSION=8-jdk21
10
+ ARG JRE_VERSION=21-jre
11
+
12
+ # Stage 1: Build
13
+ FROM gradle:${GRADLE_VERSION} AS builder
14
+
15
+ WORKDIR /app
16
+
17
+ COPY --chown=gradle:gradle build.gradle* settings.gradle* ./
18
+ COPY --chown=gradle:gradle src ./src
19
+ RUN gradle --no-daemon clean build -x test
20
+
21
+ # Stage 2: Runtime
22
+ FROM eclipse-temurin:${JRE_VERSION}
23
+
24
+ LABEL security.scanner="dockerls"
25
+ LABEL security.hardened="true"
26
+ LABEL maintainer="security@company.com"
27
+ LABEL security.cve-contact="security@company.com"
28
+
29
+ ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
30
+
31
+ RUN apt-get update && apt-get upgrade -y --no-install-recommends \
32
+ && rm -rf /var/lib/apt/lists/* \
33
+ && groupadd -g 10001 appgroup \
34
+ && useradd -u 10001 -g appgroup -s /usr/sbin/nologin -m appuser
35
+
36
+ WORKDIR /app
37
+
38
+ COPY --from=builder --chown=appuser:appgroup /app/build/libs/*.jar /app/app.jar
39
+
40
+ ARG GIT_SHA=unknown
41
+ ARG BUILD_TIME=unknown
42
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
43
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
44
+
45
+ USER appuser
46
+
47
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
48
+ CMD [ -f /app/app.jar ] || exit 1
49
+
50
+ EXPOSE 8080
51
+
52
+ ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -jar /app/app.jar"]
@@ -0,0 +1,50 @@
1
+ # Dockerfile.hardened.java-alpine
2
+ # Hardened template for Java 21 (Eclipse Temurin JRE Alpine)
3
+
4
+ ARG JDK_VERSION=21-jdk-alpine
5
+ ARG JRE_VERSION=21-jre-alpine
6
+
7
+ # Stage 1: Build (Maven / Gradle)
8
+ FROM eclipse-temurin:${JDK_VERSION} AS builder
9
+
10
+ WORKDIR /app
11
+
12
+ RUN apk add --no-cache maven gradle \
13
+ && rm -rf /var/cache/apk/*
14
+
15
+ COPY pom.xml ./
16
+ COPY src ./src
17
+ RUN mvn clean package -DskipTests || true
18
+
19
+ # Stage 2: Runtime
20
+ FROM eclipse-temurin:${JRE_VERSION}
21
+
22
+ LABEL security.scanner="dockerls"
23
+ LABEL security.hardened="true"
24
+ LABEL maintainer="security@company.com"
25
+ LABEL security.cve-contact="security@company.com"
26
+
27
+ ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
28
+
29
+ RUN apk update && apk upgrade --no-cache \
30
+ && addgroup -g 10001 appgroup \
31
+ && adduser -u 10001 -G appgroup -s /sbin/nologin -D appuser \
32
+ && rm -rf /var/cache/apk/*
33
+
34
+ WORKDIR /app
35
+
36
+ COPY --from=builder --chown=appuser:appgroup /app/target/*.jar /app/app.jar
37
+
38
+ ARG GIT_SHA=unknown
39
+ ARG BUILD_TIME=unknown
40
+ LABEL org.opencontainers.image.revision="${GIT_SHA}"
41
+ LABEL org.opencontainers.image.created="${BUILD_TIME}"
42
+
43
+ USER appuser
44
+
45
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
46
+ CMD [ -f /app/app.jar ] || exit 1
47
+
48
+ EXPOSE 8080
49
+
50
+ ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -jar /app/app.jar"]