ce7cb702218693d08ea6d83464d2457c9250027c

This commit is contained in:
ms2k 2026-11-12 20:46:28 +09:00
commit 34c5f8963c
10 changed files with 145336 additions and 0 deletions

19
vendor/platform/quay/certificate.yaml vendored Normal file
View file

@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: quay-registry
namespace: quay
spec:
secretName: quay-registry-tls
issuerRef:
name: vault-internal
kind: ClusterIssuer
commonName: registry.quorate.internal
dnsNames:
- registry.quorate.internal
duration: 2160h
renewBefore: 360h
privateKey:
algorithm: ECDSA
size: 256
rotationPolicy: Always

232
vendor/platform/quay/clair.yaml vendored Normal file
View file

@ -0,0 +1,232 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: quay-registry-clair
namespace: quay
labels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-operator/quayregistry: quay-registry
---
apiVersion: v1
kind: Service
metadata:
name: quay-registry-clair-app
namespace: quay
labels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-component: clair-app
quay-operator/quayregistry: quay-registry
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-component: clair-app
quay-operator/quayregistry: quay-registry
ports:
- name: clair-http
port: 80
protocol: TCP
targetPort: clair-http
- name: clair-introspection
port: 8089
protocol: TCP
targetPort: clair-intro
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: quay-registry-clair
namespace: quay
labels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-component: clair-app
quay-operator/quayregistry: quay-registry
spec:
replicas: 2
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-component: clair-app
quay-operator/quayregistry: quay-registry
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
template:
metadata:
labels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-component: clair-app
quay-operator/quayregistry: quay-registry
spec:
serviceAccountName: quay-registry-clair
imagePullSecrets:
- name: quay-cluster-pull
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
fsGroup: 65534
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: has-zfs
operator: In
values:
- "true"
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: quay-component
operator: In
values:
- clair-app
topologyKey: kubernetes.io/hostname
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-component: clair-app
quay-operator/quayregistry: quay-registry
containers:
- name: clair-app
image: registry.quorate.internal/quorate/clair@sha256:b3040b6c61df5b6a261c981d2fb9c794244879b01e9842806cb8f11dbdc28bde
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
env:
- name: CLAIR_CONF
value: /clair/config.yaml
- name: CLAIR_MODE
value: combo
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: clair-db
key: password
- name: SSL_CERT_FILE
value: /var/run/certs/internal-ca.crt
ports:
- name: clair-http
containerPort: 8080
protocol: TCP
- name: clair-intro
containerPort: 8089
protocol: TCP
startupProbe:
tcpSocket:
port: clair-intro
failureThreshold: 300
periodSeconds: 10
timeoutSeconds: 1
readinessProbe:
tcpSocket:
port: clair-http
failureThreshold: 3
periodSeconds: 10
timeoutSeconds: 1
livenessProbe:
httpGet:
path: /healthz
port: clair-intro
scheme: HTTP
failureThreshold: 3
periodSeconds: 10
timeoutSeconds: 1
resources:
requests:
cpu: "2"
memory: 2Gi
limits:
cpu: "4"
memory: 16Gi
volumeMounts:
- name: config
mountPath: /clair/config.yaml
subPath: config.yaml
readOnly: true
- name: internal-ca
mountPath: /var/run/certs/internal-ca.crt
subPath: internal-ca.crt
readOnly: true
- name: indexer-layer-storage
mountPath: /var/tmp
volumes:
- name: config
secret:
secretName: quay-config-bundle
items:
- key: clair-config.yaml
path: config.yaml
- name: internal-ca
secret:
secretName: quay-config-bundle
items:
- key: extra_ca_cert_internal-ca.crt
path: internal-ca.crt
- name: indexer-layer-storage
emptyDir:
sizeLimit: 20Gi
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: quay-registry-clair-app
namespace: quay
labels:
app.kubernetes.io/name: clair
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: security-scanner
quay-operator/quayregistry: quay-registry
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: quay-registry-clair
minReplicas: 2
maxReplicas: 2
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 90
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 90

31
vendor/platform/quay/hpa.yaml vendored Normal file
View file

@ -0,0 +1,31 @@
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: quay-registry-quay-app
namespace: quay
labels:
app.kubernetes.io/name: quay
app.kubernetes.io/instance: quay-registry
app.kubernetes.io/component: app
quay-operator/quayregistry: quay-registry
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: quay-registry-quay-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 90
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 90

12
vendor/platform/quay/kustomization.yaml vendored Normal file
View file

@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- serviceaccount.yaml
- certificate.yaml
- vso.yaml
- clair.yaml
- hpa.yaml
- service.yaml
- registry.yaml
- route.yaml
- network-policies.yaml

View file

@ -0,0 +1,174 @@
---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: quay
namespace: quay
spec:
endpointSelector:
matchExpressions:
- key: name
operator: NotIn
values:
- quay-operator-alm-owned
ingress:
- fromEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: quay
- fromEntities:
- host
- kube-apiserver
- remote-node
- fromEntities:
- ingress
toPorts:
- ports:
- port: "80"
protocol: TCP
- port: "8080"
protocol: TCP
- port: "443"
protocol: TCP
- fromEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
gateway.networking.k8s.io/gateway-name: gateway-internal
toPorts:
- ports:
- port: "80"
protocol: TCP
- port: "8080"
protocol: TCP
- port: "443"
protocol: TCP
# Direct LAN/WireGuard clients reach Quay through quay-direct LoadBalancer.
- fromCIDR:
- 10.115.187.218/24
- 10.63.81.107/24
- 10.162.8.60/24
toPorts:
- ports:
- port: "8443"
protocol: TCP
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: quay
- toEntities:
- kube-apiserver
toPorts:
- ports:
- port: "6443"
protocol: TCP
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
- port: "53"
protocol: TCP
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: postgres
cnpg.io/cluster: main
toPorts:
- ports:
- port: "5432"
protocol: TCP
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: versitygw
app.kubernetes.io/name: versitygw
app.kubernetes.io/instance: versitygw
toPorts:
- ports:
- port: "7070"
protocol: TCP
# In-cluster clients reach S3 through versitygw-direct BGP LoadBalancer (socket-LB VIP).
- toCIDR:
- 10.66.127.81/32
toPorts:
- ports:
- port: "443"
protocol: TCP
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: dragonfly
app.kubernetes.io/name: dragonfly
app: quay
toPorts:
- ports:
- port: "6379"
protocol: TCP
- toEntities:
- world
toPorts:
- ports:
- port: "443"
protocol: TCP
---
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: gateway-internal-egress-quay
spec:
endpointSelector:
matchLabels:
"reserved:ingress": ""
egress:
- toEndpoints:
- matchExpressions:
- key: k8s:io.kubernetes.pod.namespace
operator: In
values: ["quay"]
- key: name
operator: NotIn
values: ["quay-operator-alm-owned"]
toPorts:
- ports:
- port: "80"
protocol: TCP
- port: "8080"
protocol: TCP
- port: "443"
protocol: TCP
---
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: host-egress-quay
spec:
nodeSelector: {}
egress:
- toEndpoints:
- matchExpressions:
- key: k8s:io.kubernetes.pod.namespace
operator: In
values: ["quay"]
- key: name
operator: NotIn
values: ["quay-operator-alm-owned"]
---
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: host-ingress-quay-replies
spec:
nodeSelector: {}
ingress:
- fromEndpoints:
- matchExpressions:
- key: k8s:io.kubernetes.pod.namespace
operator: In
values: ["quay"]
- key: name
operator: NotIn
values: ["quay-operator-alm-owned"]
toPorts:
- ports:
- port: "32768"
endPort: 60999
protocol: TCP

58
vendor/platform/quay/registry.yaml vendored Normal file
View file

@ -0,0 +1,58 @@
apiVersion: quay.redhat.com/v1
kind: QuayRegistry
metadata:
name: quay-registry
namespace: quay
spec:
configBundleSecret: quay-config-bundle
components:
- kind: quay
managed: true
overrides:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
quay-component: quay-app
topologyKey: kubernetes.io/hostname
labels:
app.kubernetes.io/name: quay
app.kubernetes.io/instance: quay-registry
gateway.quorate.internal/allow-gateway-client: "true"
quorate.dev/zitadel-relay: "true"
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
memory: 8Gi
env:
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: quay-db
key: password
- kind: postgres
managed: false
- kind: clair
managed: false
- kind: clairpostgres
managed: false
- kind: redis
managed: false
- kind: objectstorage
managed: false
- kind: route
managed: false
- kind: tls
managed: false
secretRef:
name: quay-registry-tls
- kind: monitoring
managed: false
- kind: mirror
managed: false
- kind: horizontalpodautoscaler
managed: false

16
vendor/platform/quay/route.yaml vendored Normal file
View file

@ -0,0 +1,16 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: quay
namespace: quay
spec:
parentRefs:
- name: gateway-internal
namespace: kube-system
sectionName: https
hostnames:
- registry.quorate.internal
rules:
- backendRefs:
- name: quay-registry-quay-app
port: 80

29
vendor/platform/quay/service.yaml vendored Normal file
View file

@ -0,0 +1,29 @@
apiVersion: v1
kind: Service
metadata:
name: quay-direct
namespace: quay
labels:
app: quay
quay-component: quay-app
quay-operator/quayregistry: quay-registry
io.cilium/bgp-announce: "true"
annotations:
lbipam.cilium.io/ips: "10.108.252.250"
spec:
type: LoadBalancer
externalTrafficPolicy: Local
loadBalancerSourceRanges:
- 10.115.187.218/24
- 10.63.81.107/24
- 10.162.8.60/24
selector:
app: quay
quay-component: quay-app
quay-operator/quayregistry: quay-registry
ports:
- name: https
port: 443
targetPort: 8443
protocol: TCP
appProtocol: https

View file

@ -0,0 +1,5 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: quay-vso
namespace: quay

220
vendor/platform/quay/vso.yaml vendored Normal file
View file

@ -0,0 +1,220 @@
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: default
namespace: quay
spec:
method: kubernetes
mount: kubernetes
kubernetes:
role: quay
serviceAccount: quay-vso
vaultConnectionRef: vault/vault
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: quay-config-bundle
namespace: quay
spec:
type: kv-v2
mount: secret
path: quay/secrets
destination:
name: quay-config-bundle
create: true
overwrite: true
transformation:
excludeRaw: true
excludes:
- .*
templates:
config.yaml:
text: |
AUTHENTICATION_TYPE: OIDC
BROWSER_API_CALLS_XHR_ONLY: false
DATABASE_SECRET_KEY: "{{ get .Secrets "database_secret_key" }}"
DB_URI: "postgresql://********@main-rw.postgres.svc.cluster.local:5432/quay?sslmode=require"
BUILDLOGS_REDIS:
host: quay.dragonfly.svc.cluster.local
password: "{{ get .Secrets "redis_password" }}"
port: 6379
DISTRIBUTED_STORAGE_CONFIG:
default:
- RadosGWStorage
- access_key: quay
secret_key: "{{ get .Secrets "s3_secret_key" }}"
bucket_name: quay-registry
hostname: s3.quorate.internal
is_secure: true
signature_version: v4
storage_path: /datastorage/registry
server_side_assembly: false
DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: []
DISTRIBUTED_STORAGE_PREFERENCE: ["default"]
EXTERNAL_TLS_TERMINATION: false
FEATURE_SECURITY_NOTIFICATIONS: true
FEATURE_SECURITY_SCANNER: true
FEATURE_SECURITY_SCANNER_NOTIFY_ON_NEW_INDEX: true
FEATURE_PROXY_CACHE: false
FEATURE_USER_CREATION: true
FEATURE_USER_INITIALIZE: true
PREFERRED_URL_SCHEME: https
SECRET_KEY: "{{ get .Secrets "secret_key" }}"
SECURITY_SCANNER_INDEXING_INTERVAL: 30
SECURITY_SCANNER_V4_ENDPOINT: http://quay-registry-clair-app.quay.svc.cluster.local
SECURITY_SCANNER_V4_INDEX_MAX_LAYER_SIZE: 8G
SECURITY_SCANNER_V4_MANIFEST_CLEANUP: true
SECURITY_SCANNER_V4_PSK: "{{ get .Secrets "clair_psk" }}"
SERVER_HOSTNAME: registry.quorate.internal
SUPER_USERS: ["********"]
USER_EVENTS_REDIS:
host: quay.dragonfly.svc.cluster.local
password: "{{ get .Secrets "redis_password" }}"
port: 6379
ZITADEL_LOGIN_CONFIG:
CLIENT_ID: "{{ get .Secrets "oidc_client_id" }}"
CLIENT_SECRET: "{{ get .Secrets "oidc_client_secret" }}"
LOGIN_SCOPES: ["openid", "email", "profile"]
OIDC_ISSUER: https://auth.quorate.dev
OIDC_SERVER: https://auth.quorate.dev/
PREFERRED_GROUP_CLAIM_NAME: groups
PREFERRED_USERNAME_CLAIM_NAME: preferred_username
SERVICE_NAME: Zitadel
clair-config.yaml:
text: |
http_listen_addr: :8080
introspection_addr: :8089
log_level: info
indexer:
connstring: "host=main-rw.postgres.svc.cluster.local port=5432 dbname=quay_clair user=******** sslmode=require"
scanlock_retry: 10
layer_scan_concurrency: 5
migrations: true
scanner:
package:
java:
api: https://central.sonatype.com/solrsearch/select
matcher:
connstring: "host=main-rw.postgres.svc.cluster.local port=5432 dbname=quay_clair user=******** sslmode=require"
migrations: true
notifier:
connstring: "host=main-rw.postgres.svc.cluster.local port=5432 dbname=quay_clair user=******** sslmode=require"
delivery_interval: 1m
migrations: true
poll_interval: 5m
webhook:
callback: http://quay-registry-clair-app/notifier/api/v1/notifications
target: https://registry.quorate.internal/secscan/notification
auth:
psk:
key: "{{ get .Secrets "clair_psk" }}"
iss: ["quay", "clairctl"]
updaters:
config:
rhel-vex:
ignore_unpatched: true
sets:
- alpine
- clair.cvss
- debian
- oracle
- photon
- rhcc
- rhel-vex
- suse
- ubuntu
metrics:
name: prometheus
extra_ca_cert_internal-ca.crt:
text: |
{{- get .Secrets "internal_ca_cert" -}}
refreshAfter: 1h
rolloutRestartTargets:
- kind: Deployment
name: quay-registry-quay-app
- kind: Deployment
name: quay-registry-clair
vaultAuthRef: default
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: quay-db
namespace: quay
spec:
mount: database
path: static-creds/quay
allowStaticCreds: true
destination:
name: quay-db
create: true
overwrite: true
transformation:
excludeRaw: true
excludes:
- .*
templates:
username:
text: '{{ get .Secrets "username" }}'
password:
text: '{{ get .Secrets "password" }}'
refreshAfter: 1h
rolloutRestartTargets:
- kind: Deployment
name: quay-registry-quay-app
vaultAuthRef: default
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: clair-db
namespace: quay
spec:
mount: database
path: static-creds/quay_clair
allowStaticCreds: true
destination:
name: clair-db
create: true
overwrite: true
transformation:
excludeRaw: true
excludes:
- .*
templates:
username:
text: '{{ get .Secrets "username" }}'
password:
text: '{{ get .Secrets "password" }}'
refreshAfter: 1h
rolloutRestartTargets:
- kind: Deployment
name: quay-registry-clair
vaultAuthRef: default
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: quay-cluster-pull
namespace: quay
spec:
type: kv-v2
mount: secret
path: quay/robots/cluster_pull
refreshAfter: 1h
destination:
name: quay-cluster-pull
create: true
overwrite: true
type: kubernetes.io/dockerconfigjson
transformation:
excludeRaw: true
excludes: [.*]
templates:
.dockerconfigjson:
text: >-
{"auths":{"registry.quorate.internal":{"auth":"{{ printf "%s:%s" (get .Secrets "username") (get .Secrets "token") | b64enc }}"}}}
vaultAuthRef: default