diff --git a/Dockerfile b/Dockerfile index 17c7b7ed..bc2be9f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,8 +31,11 @@ COPY --from=build-env /work/out/pinniped-concierge /usr/local/bin/pinniped-conci COPY --from=build-env /work/out/pinniped-supervisor /usr/local/bin/pinniped-supervisor COPY --from=build-env /work/out/local-user-authenticator /usr/local/bin/local-user-authenticator -# Document the port -EXPOSE 443 +# Document the ports +EXPOSE 8080 8443 + +# Run as non-root for security posture +USER 1001:1001 # Set the entrypoint ENTRYPOINT ["/usr/local/bin/pinniped-concierge"] diff --git a/cmd/local-user-authenticator/main.go b/cmd/local-user-authenticator/main.go index f226066f..c88dbf3c 100644 --- a/cmd/local-user-authenticator/main.go +++ b/cmd/local-user-authenticator/main.go @@ -375,7 +375,7 @@ func run() error { klog.InfoS("controllers are ready") //nolint: gosec // Intentionally binding to all network interfaces. - l, err := net.Listen("tcp", ":443") + l, err := net.Listen("tcp", ":8443") if err != nil { return fmt.Errorf("cannot create listener: %w", err) } diff --git a/cmd/pinniped-supervisor/main.go b/cmd/pinniped-supervisor/main.go index 1a38120d..5f7932df 100644 --- a/cmd/pinniped-supervisor/main.go +++ b/cmd/pinniped-supervisor/main.go @@ -198,7 +198,7 @@ func run(serverInstallationNamespace string, cfg *supervisor.Config) error { ) //nolint: gosec // Intentionally binding to all network interfaces. - httpListener, err := net.Listen("tcp", ":80") + httpListener, err := net.Listen("tcp", ":8080") if err != nil { return fmt.Errorf("cannot create listener: %w", err) } @@ -206,12 +206,12 @@ func run(serverInstallationNamespace string, cfg *supervisor.Config) error { start(ctx, httpListener, oidProvidersManager) //nolint: gosec // Intentionally binding to all network interfaces. - httpsListener, err := tls.Listen("tcp", ":443", &tls.Config{ + httpsListener, err := tls.Listen("tcp", ":8443", &tls.Config{ MinVersion: tls.VersionTLS12, // Allow v1.2 because clients like the default `curl` on MacOS don't support 1.3 yet. GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { cert := dynamicTLSCertProvider.GetTLSCert(strings.ToLower(info.ServerName)) defaultCert := dynamicTLSCertProvider.GetDefaultTLSCert() - klog.InfoS("GetCertificate called for port 443", + klog.InfoS("GetCertificate called for port 8443", "info.ServerName", info.ServerName, "foundSNICert", cert != nil, "foundDefaultCert", defaultCert != nil, diff --git a/deploy/concierge/deployment.yaml b/deploy/concierge/deployment.yaml index d8e8c071..4d2755d9 100644 --- a/deploy/concierge/deployment.yaml +++ b/deploy/concierge/deployment.yaml @@ -86,6 +86,9 @@ spec: annotations: scheduler.alpha.kubernetes.io/critical-pod: "" spec: + securityContext: + runAsUser: 1001 + runAsGroup: 1001 serviceAccountName: #@ defaultResourceName() #@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "": imagePullSecrets: @@ -113,7 +116,7 @@ spec: livenessProbe: httpGet: path: /healthz - port: 443 + port: 8443 scheme: HTTPS initialDelaySeconds: 2 timeoutSeconds: 15 @@ -122,7 +125,7 @@ spec: readinessProbe: httpGet: path: /healthz - port: 443 + port: 8443 scheme: HTTPS initialDelaySeconds: 2 timeoutSeconds: 3 @@ -173,7 +176,7 @@ spec: ports: - protocol: TCP port: 443 - targetPort: 443 + targetPort: 8443 --- apiVersion: apiregistration.k8s.io/v1 kind: APIService diff --git a/deploy/local-user-authenticator/deployment.yaml b/deploy/local-user-authenticator/deployment.yaml index 71a21701..73fc2c50 100644 --- a/deploy/local-user-authenticator/deployment.yaml +++ b/deploy/local-user-authenticator/deployment.yaml @@ -47,6 +47,9 @@ spec: labels: app: local-user-authenticator spec: + securityContext: + runAsUser: 1001 + runAsGroup: 1001 serviceAccountName: local-user-authenticator #@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "": imagePullSecrets: @@ -77,4 +80,4 @@ spec: ports: - protocol: TCP port: 443 - targetPort: 443 + targetPort: 8443 diff --git a/deploy/supervisor/README.md b/deploy/supervisor/README.md index 6b022a07..20b86d29 100644 --- a/deploy/supervisor/README.md +++ b/deploy/supervisor/README.md @@ -47,7 +47,7 @@ The most common ways are: 1. Define an [`Ingress` resource](https://kubernetes.io/docs/concepts/services-networking/ingress/) with TLS certificates. In this case, the ingress will terminate TLS. Typically, the ingress will then talk plain HTTP to its backend, - which would be a NodePort or LoadBalancer Service in front of the HTTP port 80 of the Supervisor pods. + which would be a NodePort or LoadBalancer Service in front of the HTTP port 8080 of the Supervisor pods. The required configuration of the Ingress is specific to your cluster's Ingress Controller, so please refer to the documentation from your Kubernetes provider. If you are using a cluster from a cloud provider, then you'll probably @@ -60,10 +60,10 @@ The most common ways are: 1. Or, define a [TCP LoadBalancer Service](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer) which is a layer 4 load balancer and does not terminate TLS. In this case, the Supervisor app will need to be configured with TLS certificates and will terminate the TLS connection itself (see the section about - OIDCProviderConfig below). The LoadBalancer Service should be configured to use the HTTPS port 443 of + OIDCProviderConfig below). The LoadBalancer Service should be configured to use the HTTPS port 8443 of the Supervisor pods as its `targetPort`. - *Warning:* Do not expose the Supervisor's port 80 to the public. It would not be secure for the OIDC protocol + *Warning:* Do not expose the Supervisor's port 8080 to the public. It would not be secure for the OIDC protocol to use HTTP, because the user's secret OIDC tokens would be transmitted across the network without encryption. 1. Or, expose the Supervisor app using a Kubernetes service mesh technology, e.g. [Istio](https://istio.io/). @@ -79,7 +79,7 @@ so if you choose to use an Ingress then you'll need to create that separately af #### Example: Using a LoadBalancer Service -This is an example of creating a LoadBalancer Service to expose port 443 of the Supervisor app outside the cluster. +This is an example of creating a LoadBalancer Service to expose port 8443 of the Supervisor app outside the cluster. ```yaml apiVersion: v1 @@ -96,7 +96,7 @@ spec: ports: - protocol: TCP port: 443 - targetPort: 443 + targetPort: 8443 ``` #### Example: Using a NodePort Service @@ -127,7 +127,7 @@ spec: ports: - protocol: TCP port: 80 - targetPort: 80 + targetPort: 8080 nodePort: 31234 # This is the port that you would forward to the kind host. Or omit this key for a random port. ``` diff --git a/deploy/supervisor/deployment.yaml b/deploy/supervisor/deployment.yaml index 8f91610d..8d38a6b0 100644 --- a/deploy/supervisor/deployment.yaml +++ b/deploy/supervisor/deployment.yaml @@ -60,6 +60,9 @@ spec: metadata: labels: #@ defaultLabel() spec: + securityContext: + runAsUser: 1001 + runAsGroup: 1001 serviceAccountName: #@ defaultResourceName() #@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "": imagePullSecrets: @@ -87,14 +90,14 @@ spec: - name: podinfo mountPath: /etc/podinfo ports: - - containerPort: 80 + - containerPort: 8080 protocol: TCP - - containerPort: 443 + - containerPort: 8443 protocol: TCP livenessProbe: httpGet: path: /healthz - port: 80 + port: 8080 scheme: HTTP initialDelaySeconds: 2 timeoutSeconds: 15 @@ -103,7 +106,7 @@ spec: readinessProbe: httpGet: path: /healthz - port: 80 + port: 8080 scheme: HTTP initialDelaySeconds: 2 timeoutSeconds: 3 diff --git a/deploy/supervisor/service.yaml b/deploy/supervisor/service.yaml index d8739c40..53e9d4ca 100644 --- a/deploy/supervisor/service.yaml +++ b/deploy/supervisor/service.yaml @@ -21,7 +21,7 @@ spec: - name: http protocol: TCP port: #@ data.values.service_http_nodeport_port - targetPort: 80 + targetPort: 8080 #@ if data.values.service_http_nodeport_nodeport: nodePort: #@ data.values.service_http_nodeport_nodeport #@ end @@ -30,7 +30,7 @@ spec: - name: https protocol: TCP port: #@ data.values.service_https_nodeport_port - targetPort: 443 + targetPort: 8443 #@ if data.values.service_https_nodeport_nodeport: nodePort: #@ data.values.service_https_nodeport_nodeport #@ end @@ -53,13 +53,13 @@ spec: - name: http protocol: TCP port: #@ data.values.service_http_clusterip_port - targetPort: 80 + targetPort: 8080 #@ end #@ if data.values.service_https_clusterip_port: - name: https protocol: TCP port: #@ data.values.service_https_clusterip_port - targetPort: 443 + targetPort: 8443 #@ end #@ end @@ -82,12 +82,12 @@ spec: - name: http protocol: TCP port: #@ data.values.service_http_loadbalancer_port - targetPort: 80 + targetPort: 8080 #@ end #@ if data.values.service_https_loadbalancer_port: - name: https protocol: TCP port: #@ data.values.service_https_loadbalancer_port - targetPort: 443 + targetPort: 8443 #@ end #@ end diff --git a/deploy/supervisor/values.yaml b/deploy/supervisor/values.yaml index f9e1aac0..480d1cc1 100644 --- a/deploy/supervisor/values.yaml +++ b/deploy/supervisor/values.yaml @@ -40,14 +40,14 @@ image_pull_dockerconfigjson: #! e.g. {"auths":{"https://registry.example.com":{" #! An HTTP service should not be exposed outside the cluster. It would not be secure to serve OIDC endpoints to end users via HTTP. #! Setting any of these values means that a Service of that type will be created. #! Note that all port numbers should be numbers (not strings), i.e. use ytt's `--data-value-yaml` instead of `--data-value`. -service_http_nodeport_port: #! when specified, creates a NodePort Service with this `port` value, with port 80 as its `targetPort`; e.g. 31234 +service_http_nodeport_port: #! when specified, creates a NodePort Service with this `port` value, with port 8080 as its `targetPort`; e.g. 31234 service_http_nodeport_nodeport: #! the `nodePort` value of the NodePort Service, optional when `service_http_nodeport_port` is specified; e.g. 31234 -service_http_loadbalancer_port: #! when specified, creates a LoadBalancer Service with this `port` value, with port 80 as its `targetPort`; e.g. 443 -service_http_clusterip_port: #! when specified, creates a ClusterIP Service with this `port` value, with port 80 as its `targetPort`; e.g. 443 -service_https_nodeport_port: #! when specified, creates a NodePort Service with this `port` value, with port 443 as its `targetPort`; e.g. 31243 +service_http_loadbalancer_port: #! when specified, creates a LoadBalancer Service with this `port` value, with port 8080 as its `targetPort`; e.g. 8443 +service_http_clusterip_port: #! when specified, creates a ClusterIP Service with this `port` value, with port 8080 as its `targetPort`; e.g. 8443 +service_https_nodeport_port: #! when specified, creates a NodePort Service with this `port` value, with port 8443 as its `targetPort`; e.g. 31243 service_https_nodeport_nodeport: #! the `nodePort` value of the NodePort Service, optional when `service_http_nodeport_port` is specified; e.g. 31243 -service_https_loadbalancer_port: #! when specified, creates a LoadBalancer Service with this `port` value, with port 443 as its `targetPort`; e.g. 443 -service_https_clusterip_port: #! when specified, creates a ClusterIP Service with this `port` value, with port 443 as its `targetPort`; e.g. 443 +service_https_loadbalancer_port: #! when specified, creates a LoadBalancer Service with this `port` value, with port 8443 as its `targetPort`; e.g. 8443 +service_https_clusterip_port: #! when specified, creates a ClusterIP Service with this `port` value, with port 8443 as its `targetPort`; e.g. 8443 #! The `loadBalancerIP` value of the LoadBalancer Service. #! Ignored unless service_http_loadbalancer_port and/or service_https_loadbalancer_port are provided. #! Optional. diff --git a/hack/lib/tilt/concierge.Dockerfile b/hack/lib/tilt/concierge.Dockerfile index 3ddf4033..b24a10b5 100644 --- a/hack/lib/tilt/concierge.Dockerfile +++ b/hack/lib/tilt/concierge.Dockerfile @@ -8,7 +8,7 @@ FROM debian:10.5-slim COPY build/pinniped-concierge /usr/local/bin/pinniped-concierge # Document the port -EXPOSE 443 +EXPOSE 8443 # Set the entrypoint ENTRYPOINT ["/usr/local/bin/pinniped-concierge"] diff --git a/hack/lib/tilt/local-user-authenticator.Dockerfile b/hack/lib/tilt/local-user-authenticator.Dockerfile index 1853ccd8..5f0d314c 100644 --- a/hack/lib/tilt/local-user-authenticator.Dockerfile +++ b/hack/lib/tilt/local-user-authenticator.Dockerfile @@ -8,7 +8,7 @@ FROM debian:10.5-slim COPY build/local-user-authenticator /usr/local/bin/local-user-authenticator # Document the port -EXPOSE 443 +EXPOSE 8443 # Set the entrypoint ENTRYPOINT ["/usr/local/bin/local-user-authenticator"] diff --git a/hack/lib/tilt/supervisor.Dockerfile b/hack/lib/tilt/supervisor.Dockerfile index 22d7e204..6a18da00 100644 --- a/hack/lib/tilt/supervisor.Dockerfile +++ b/hack/lib/tilt/supervisor.Dockerfile @@ -8,7 +8,7 @@ FROM debian:10.5-slim COPY build/pinniped-supervisor /usr/local/bin/pinniped-supervisor # Document the port -EXPOSE 443 +EXPOSE 8443 # Set the entrypoint ENTRYPOINT ["/usr/local/bin/pinniped-supervisor"] diff --git a/internal/concierge/server/server.go b/internal/concierge/server/server.go index b3667b4d..62afbb57 100644 --- a/internal/concierge/server/server.go +++ b/internal/concierge/server/server.go @@ -173,6 +173,7 @@ func getAggregatedAPIServerConfig( ) recommendedOptions.Etcd = nil // turn off etcd storage because we don't need it yet recommendedOptions.SecureServing.ServerCert.GeneratedCert = dynamicCertProvider + recommendedOptions.SecureServing.BindPort = 8443 // Don't run on default 443 because that requires root serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs) // Note that among other things, this ApplyTo() function copies diff --git a/test/integration/supervisor_discovery_test.go b/test/integration/supervisor_discovery_test.go index 78fbc214..1975ec8d 100644 --- a/test/integration/supervisor_discovery_test.go +++ b/test/integration/supervisor_discovery_test.go @@ -32,13 +32,13 @@ import ( "go.pinniped.dev/test/library" ) -// This test is intended to exercise the supervisor's HTTP port 80. It can either access it directly via +// This test is intended to exercise the supervisor's HTTP port 8080. It can either access it directly via // the env.SupervisorHTTPAddress setting, or it can access it indirectly through a TLS-enabled Ingress which -// uses the supervisor's port 80 as its backend via the env.SupervisorHTTPSIngressAddress and +// uses the supervisor's port 8080 as its backend via the env.SupervisorHTTPSIngressAddress and // env.SupervisorHTTPSIngressCABundle settings, or it can exercise it both ways when all of those // env settings are present. // -// Testing talking to the supervisor's port 443 where the supervisor is terminating TLS itself is +// Testing talking to the supervisor's port 8443 where the supervisor is terminating TLS itself is // handled by the others tests in this file. func TestSupervisorOIDCDiscovery(t *testing.T) { env := library.IntegrationEnv(t) @@ -155,7 +155,7 @@ func TestSupervisorTLSTerminationWithSNI(t *testing.T) { temporarilyRemoveAllOIDCProviderConfigsAndDefaultTLSCertSecret(ctx, t, ns, defaultTLSCertSecretName(env), pinnipedClient, kubeClient) scheme := "https" - address := env.SupervisorHTTPSAddress // hostname and port for direct access to the supervisor's port 443 + address := env.SupervisorHTTPSAddress // hostname and port for direct access to the supervisor's port 8443 hostname1 := strings.Split(address, ":")[0] issuer1 := fmt.Sprintf("%s://%s/issuer1", scheme, address) @@ -222,12 +222,12 @@ func TestSupervisorTLSTerminationWithDefaultCerts(t *testing.T) { temporarilyRemoveAllOIDCProviderConfigsAndDefaultTLSCertSecret(ctx, t, ns, defaultTLSCertSecretName(env), pinnipedClient, kubeClient) scheme := "https" - address := env.SupervisorHTTPSAddress // hostname and port for direct access to the supervisor's port 443 + address := env.SupervisorHTTPSAddress // hostname and port for direct access to the supervisor's port 8443 hostAndPortSegments := strings.Split(address, ":") // hostnames are case-insensitive, so test mis-matching the case of the issuer URL and the request URL hostname := strings.ToLower(hostAndPortSegments[0]) - port := "443" + port := "8443" if len(hostAndPortSegments) > 1 { port = hostAndPortSegments[1] }