Harden app and registry workloads
This commit is contained in:
parent
f7e3065cda
commit
16069b7950
|
|
@ -24,9 +24,21 @@ spec:
|
||||||
operator: In
|
operator: In
|
||||||
values:
|
values:
|
||||||
- debian
|
- debian
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
fsGroupChangePolicy: OnRootMismatch
|
||||||
containers:
|
containers:
|
||||||
- name: registry
|
- name: registry
|
||||||
image: registry:2
|
image: registry:2
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 5000
|
- containerPort: 5000
|
||||||
name: http
|
name: http
|
||||||
|
|
@ -51,10 +63,14 @@ spec:
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: registry-vol
|
- name: registry-vol
|
||||||
mountPath: /var/lib/registry
|
mountPath: /var/lib/registry
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
volumes:
|
volumes:
|
||||||
- name: registry-vol
|
- name: registry-vol
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: registry-pvc
|
claimName: registry-pvc
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,6 @@ FROM nginx:1.27-alpine
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
COPY public/ /usr/share/nginx/html/
|
COPY public/ /usr/share/nginx/html/
|
||||||
|
|
||||||
EXPOSE 80
|
USER nginx
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 8080;
|
||||||
server_name _;
|
server_name _;
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,24 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: raspberry
|
kubernetes.io/hostname: raspberry
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 101
|
||||||
|
runAsGroup: 101
|
||||||
|
fsGroup: 101
|
||||||
|
fsGroupChangePolicy: OnRootMismatch
|
||||||
containers:
|
containers:
|
||||||
- name: demos-static
|
- name: demos-static
|
||||||
image: 192.168.100.68:30500/demos-static:latest
|
image: 192.168.100.68:30500/demos-static:latest
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 8080
|
||||||
name: http
|
name: http
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
|
|
@ -42,6 +54,20 @@ spec:
|
||||||
memory: 32Mi
|
memory: 32Mi
|
||||||
limits:
|
limits:
|
||||||
memory: 128Mi
|
memory: 128Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: nginx-cache
|
||||||
|
mountPath: /var/cache/nginx
|
||||||
|
- name: nginx-run
|
||||||
|
mountPath: /var/run
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
volumes:
|
||||||
|
- name: nginx-cache
|
||||||
|
emptyDir: {}
|
||||||
|
- name: nginx-run
|
||||||
|
emptyDir: {}
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
|
@ -53,7 +79,7 @@ spec:
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
ports:
|
ports:
|
||||||
- port: 80
|
- port: 80
|
||||||
targetPort: 80
|
targetPort: http
|
||||||
nodePort: 30081
|
nodePort: 30081
|
||||||
selector:
|
selector:
|
||||||
app: demos-static
|
app: demos-static
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,15 @@ RUN ln -sf /usr/bin/php82 /usr/bin/php
|
||||||
# Alpine keeps Apache site configs here instead of a2enmod
|
# Alpine keeps Apache site configs here instead of a2enmod
|
||||||
RUN sed -i 's/#LoadModule rewrite_module/LoadModule rewrite_module/' /etc/apache2/httpd.conf && \
|
RUN sed -i 's/#LoadModule rewrite_module/LoadModule rewrite_module/' /etc/apache2/httpd.conf && \
|
||||||
sed -i 's/#LoadModule headers_module/LoadModule headers_module/' /etc/apache2/httpd.conf && \
|
sed -i 's/#LoadModule headers_module/LoadModule headers_module/' /etc/apache2/httpd.conf && \
|
||||||
sed -i 's/DirectoryIndex index.html/DirectoryIndex index.php index.html/' /etc/apache2/httpd.conf
|
sed -i 's/DirectoryIndex index.html/DirectoryIndex index.php index.html/' /etc/apache2/httpd.conf && \
|
||||||
|
sed -i 's/^Listen 80$/Listen 8080/' /etc/apache2/httpd.conf && \
|
||||||
|
sed -i 's#^ErrorLog .*#ErrorLog /proc/self/fd/2#' /etc/apache2/httpd.conf && \
|
||||||
|
sed -i 's#^CustomLog .*#CustomLog /proc/self/fd/1 combined#' /etc/apache2/httpd.conf && \
|
||||||
|
if grep -q '^PidFile ' /etc/apache2/httpd.conf; then \
|
||||||
|
sed -i 's#^PidFile .*#PidFile /tmp/httpd.pid#' /etc/apache2/httpd.conf; \
|
||||||
|
else \
|
||||||
|
printf '\nPidFile /tmp/httpd.pid\n' >> /etc/apache2/httpd.conf; \
|
||||||
|
fi
|
||||||
|
|
||||||
# Copy files directly into Alpine's default web root
|
# Copy files directly into Alpine's default web root
|
||||||
COPY . /var/www/localhost/htdocs/
|
COPY . /var/www/localhost/htdocs/
|
||||||
|
|
@ -31,9 +39,15 @@ RUN mkdir -p /var/www/localhost/htdocs/db && \
|
||||||
|
|
||||||
# Match local user permissions for the runtime user (Alpine uses 'apache' instead of 'www-data')
|
# Match local user permissions for the runtime user (Alpine uses 'apache' instead of 'www-data')
|
||||||
RUN usermod -u 1000 apache && \
|
RUN usermod -u 1000 apache && \
|
||||||
groupmod -g 1000 apache
|
groupmod -g 1000 apache && \
|
||||||
|
mkdir -p /run/apache2 /var/log/apache2 /tmp/website-lang && \
|
||||||
|
chown -R apache:apache /run/apache2 /var/log/apache2 /tmp/website-lang /var/www/localhost/htdocs/db
|
||||||
|
|
||||||
EXPOSE 80
|
ENV WEBSITE_LANG_WRITE_DIR=/tmp/website-lang
|
||||||
|
|
||||||
|
USER apache
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
# Start Apache in the foreground
|
# Start Apache in the foreground
|
||||||
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
|
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,17 @@
|
||||||
// Include this at the top of every page.
|
// Include this at the top of every page.
|
||||||
// Provides: $lang, $text, $en, $availableLangs
|
// Provides: $lang, $text, $en, $availableLangs
|
||||||
|
|
||||||
$availableLangs = array_map(
|
$staticLangDir = __DIR__ . '/lang';
|
||||||
|
$runtimeLangDir = getenv('WEBSITE_LANG_WRITE_DIR') ?: null;
|
||||||
|
$langFiles = glob($staticLangDir . '/*.php') ?: [];
|
||||||
|
if ($runtimeLangDir && is_dir($runtimeLangDir)) {
|
||||||
|
$langFiles = array_merge($langFiles, glob($runtimeLangDir . '/*.php') ?: []);
|
||||||
|
}
|
||||||
|
|
||||||
|
$availableLangs = array_values(array_unique(array_map(
|
||||||
fn($f) => basename($f, '.php'),
|
fn($f) => basename($f, '.php'),
|
||||||
glob(__DIR__ . '/lang/*.php')
|
$langFiles
|
||||||
);
|
)));
|
||||||
|
|
||||||
function getLang($supported) {
|
function getLang($supported) {
|
||||||
if (isset($_GET['lang']) && in_array($_GET['lang'], $supported)) {
|
if (isset($_GET['lang']) && in_array($_GET['lang'], $supported)) {
|
||||||
|
|
@ -18,12 +25,15 @@ function getLang($supported) {
|
||||||
|
|
||||||
$lang = getLang($availableLangs);
|
$lang = getLang($availableLangs);
|
||||||
|
|
||||||
$file = __DIR__ . "/lang/$lang.php";
|
$file = $runtimeLangDir ? "$runtimeLangDir/$lang.php" : '';
|
||||||
|
if (!$file || !file_exists($file)) {
|
||||||
|
$file = "$staticLangDir/$lang.php";
|
||||||
|
}
|
||||||
if (!file_exists($file)) {
|
if (!file_exists($file)) {
|
||||||
$lang = 'nah';
|
$lang = 'nah';
|
||||||
$file = __DIR__ . "/lang/nah.php";
|
$file = "$staticLangDir/nah.php";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always load English as translation source
|
// Always load English as translation source
|
||||||
$en = include __DIR__ . '/lang/en.php';
|
$en = include "$staticLangDir/en.php";
|
||||||
$text = array_replace($en, include $file);
|
$text = array_replace($en, include $file);
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,18 @@ foreach ($base as $key => $value) {
|
||||||
$lines[] = "];";
|
$lines[] = "];";
|
||||||
$content = implode("\n", $lines) . "\n";
|
$content = implode("\n", $lines) . "\n";
|
||||||
|
|
||||||
$path = __DIR__ . "/lang/$lang.php";
|
$langDir = getenv('WEBSITE_LANG_WRITE_DIR') ?: (__DIR__ . '/lang');
|
||||||
if (file_put_contents($path, $content) === false) {
|
if (!is_dir($langDir) && !mkdir($langDir, 0755, true)) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['error' => 'Could not write file — check permissions on lang/']);
|
echo json_encode(['error' => 'Could not create language directory']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode(['success' => true, 'lang' => $lang, 'path' => "lang/$lang.php"]);
|
$path = "$langDir/$lang.php";
|
||||||
|
if (file_put_contents($path, $content) === false) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 'Could not write language file']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'lang' => $lang]);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,12 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
kubernetes.io/hostname: raspberry
|
kubernetes.io/hostname: raspberry
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
fsGroupChangePolicy: OnRootMismatch
|
||||||
affinity:
|
affinity:
|
||||||
podAntiAffinity:
|
podAntiAffinity:
|
||||||
preferredDuringSchedulingIgnoredDuringExecution: # requiredDuringSchedulingIgnoredDuringExecution:
|
preferredDuringSchedulingIgnoredDuringExecution: # requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
|
@ -38,8 +44,17 @@ spec:
|
||||||
- name: php-app
|
- name: php-app
|
||||||
image: 192.168.100.68:30500/php-website:latest
|
image: 192.168.100.68:30500/php-website:latest
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
env:
|
||||||
|
- name: WEBSITE_LANG_WRITE_DIR
|
||||||
|
value: /tmp/website-lang
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 8080
|
||||||
name: http
|
name: http
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
|
|
@ -59,6 +74,24 @@ spec:
|
||||||
memory: 64Mi
|
memory: 64Mi
|
||||||
limits:
|
limits:
|
||||||
memory: 256Mi
|
memory: 256Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: apache-run
|
||||||
|
mountPath: /run/apache2
|
||||||
|
- name: apache-logs
|
||||||
|
mountPath: /var/log/apache2
|
||||||
|
- name: website-db
|
||||||
|
mountPath: /var/www/localhost/htdocs/db
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
volumes:
|
||||||
|
- name: apache-run
|
||||||
|
emptyDir: {}
|
||||||
|
- name: apache-logs
|
||||||
|
emptyDir: {}
|
||||||
|
- name: website-db
|
||||||
|
emptyDir: {}
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
|
@ -70,7 +103,7 @@ spec:
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
ports:
|
ports:
|
||||||
- port: 80
|
- port: 80
|
||||||
targetPort: 80
|
targetPort: http
|
||||||
nodePort: 30080
|
nodePort: 30080
|
||||||
selector:
|
selector:
|
||||||
app: php-website
|
app: php-website
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue