apiVersion: v1 kind: Namespace metadata: name: artifactory labels: name: artifactory --- # Network Policy for Artifactory Services # Allows internal network (192.168.100.0/24) full access # Restricts external access to health endpoints only apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: artifactory-access-control namespace: artifactory spec: podSelector: matchLabels: tier: artifactory policyTypes: - Ingress - Egress ingress: # Rule 1: Allow full access from internal network - from: - ipBlock: cidr: 192.168.100.0/24 ports: - protocol: TCP port: 8000 # Arti-API - protocol: TCP port: 8080 # Chart Museum - protocol: TCP port: 5000 # Docker Registry # Rule 2: Allow inter-pod communication within namespace - from: - namespaceSelector: matchLabels: name: artifactory - podSelector: {} ports: - protocol: TCP port: 8000 - protocol: TCP port: 8080 - protocol: TCP port: 5000 # Rule 3: Allow external access to health endpoints only # Note: This allows access to all ports but should be combined # with Ingress controller path filtering for full security - from: [] ports: - protocol: TCP port: 8000 # For /health endpoint - protocol: TCP port: 8080 # For /health endpoint - protocol: TCP port: 5000 # For /v2/ endpoint egress: # Allow DNS resolution - to: [] ports: - protocol: TCP port: 53 - protocol: UDP port: 53 # Allow outbound HTTP/HTTPS for package downloads - to: [] ports: - protocol: TCP port: 80 - protocol: TCP port: 443 # Allow inter-pod communication - to: - namespaceSelector: matchLabels: name: artifactory - podSelector: {} --- # Ingress with path-based restrictions apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: artifactory-ingress namespace: artifactory annotations: kubernetes.io/ingress.class: "nginx" # Configuration to restrict external access to specific paths nginx.ingress.kubernetes.io/configuration-snippet: | # Allow internal network full access if ($remote_addr ~ "^192\.168\.100\.") { set $internal_access 1; } # For external access, only allow specific paths if ($internal_access != 1) { # Block access to management endpoints if ($uri ~ "^/(users|debian|helm|refresh|docs|redoc|openapi\.json)") { return 403 "Access denied - Internal network only"; } # Block Chart Museum API endpoints if ($uri ~ "^/api/") { return 403 "Access denied - Internal network only"; } # Block Docker Registry push/pull (only allow health check) if ($uri ~ "^/v2/.*/(manifests|blobs)") { return 403 "Access denied - Internal network only"; } } spec: rules: - host: artifactory.local http: paths: # Arti-API - path: / pathType: Prefix backend: service: name: arti-api-service port: number: 8000 - host: charts.artifactory.local http: paths: # Chart Museum - path: / pathType: Prefix backend: service: name: chartmuseum-service port: number: 8080 - host: registry.artifactory.local http: paths: # Docker Registry - path: / pathType: Prefix backend: service: name: docker-registry-service port: number: 5000 --- # Update existing deployments to include tier label apiVersion: apps/v1 kind: Deployment metadata: name: arti-api namespace: artifactory labels: app: arti-api tier: artifactory spec: replicas: 1 selector: matchLabels: app: arti-api tier: artifactory template: metadata: labels: app: arti-api tier: artifactory spec: containers: - name: arti-api image: hexah/arti-api:1.0.1 ports: - containerPort: 8000 env: - name: PYTHONUNBUFFERED value: "1" volumeMounts: - name: artifactory-storage mountPath: /data livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 5 periodSeconds: 5 resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" volumes: - name: artifactory-storage persistentVolumeClaim: claimName: artifactory-pvc --- apiVersion: v1 kind: Service metadata: name: arti-api-service namespace: artifactory labels: app: arti-api tier: artifactory spec: type: ClusterIP ports: - port: 8000 targetPort: 8000 protocol: TCP selector: app: arti-api tier: artifactory --- apiVersion: apps/v1 kind: Deployment metadata: name: chartmuseum namespace: artifactory labels: app: chartmuseum tier: artifactory spec: replicas: 1 selector: matchLabels: app: chartmuseum tier: artifactory template: metadata: labels: app: chartmuseum tier: artifactory spec: containers: - name: chartmuseum image: chartmuseum/chartmuseum:latest ports: - containerPort: 8080 env: - name: STORAGE value: "local" - name: STORAGE_LOCAL_ROOTDIR value: "/data/charts" - name: PORT value: "8080" - name: AUTH_ANONYMOUS_GET value: "false" - name: HTPASSWD_PATH value: "/data/htpasswd" - name: AUTH_REALM value: "Chart Museum" - name: ALLOW_OVERWRITE value: "true" - name: DISABLE_API value: "false" volumeMounts: - name: artifactory-storage mountPath: /data livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 5 resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" volumes: - name: artifactory-storage persistentVolumeClaim: claimName: artifactory-pvc --- apiVersion: v1 kind: Service metadata: name: chartmuseum-service namespace: artifactory labels: app: chartmuseum tier: artifactory spec: type: ClusterIP ports: - port: 8080 targetPort: 8080 protocol: TCP selector: app: chartmuseum tier: artifactory --- apiVersion: apps/v1 kind: Deployment metadata: name: docker-registry namespace: artifactory labels: app: docker-registry tier: artifactory spec: replicas: 1 selector: matchLabels: app: docker-registry tier: artifactory template: metadata: labels: app: docker-registry tier: artifactory spec: containers: - name: registry image: registry:2 ports: - containerPort: 5000 env: - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY value: "/data/docker" - name: REGISTRY_AUTH value: "htpasswd" - name: REGISTRY_AUTH_HTPASSWD_REALM value: "Registry Realm" - name: REGISTRY_AUTH_HTPASSWD_PATH value: "/data/htpasswd" - name: REGISTRY_HTTP_ADDR value: "0.0.0.0:5000" volumeMounts: - name: artifactory-storage mountPath: /data livenessProbe: httpGet: path: /v2/ port: 5000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /v2/ port: 5000 initialDelaySeconds: 5 periodSeconds: 5 resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" volumes: - name: artifactory-storage persistentVolumeClaim: claimName: artifactory-pvc --- apiVersion: v1 kind: Service metadata: name: docker-registry-service namespace: artifactory labels: app: docker-registry tier: artifactory spec: type: ClusterIP ports: - port: 5000 targetPort: 5000 protocol: TCP selector: app: docker-registry tier: artifactory --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: artifactory-pvc namespace: artifactory spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: "" # Specify your storage class here