goharbor / harbor

An open source trusted cloud native registry project that stores, signs, and scans content.
https://goharbor.io
Apache License 2.0
22.97k stars 4.64k forks source link

ECDSA certificates for internal tls aren't supported #20082

Open dee-kryvenko opened 3 months ago

dee-kryvenko commented 3 months ago

Expected behavior and actual behavior:

I was using cert-manager with this:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: internal-tls-ca
spec:
  isCA: true
  commonName: internal-tls-ca
  secretName: internal-tls-ca
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: self-signed
    kind: ClusterIssuer
    group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: internal-tls-issuer
spec:
  ca:
    secretName: internal-tls-ca
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: harbor-core-internal-tls
spec:
  issuerRef:
    group: cert-manager.io
    kind: Issuer
    name: internal-tls-issuer
  commonName: harbor-core
  dnsNames:
    - localhost
    - harbor-core
  ipAddresses:
    - 127.0.0.1
  usages:
    - server auth
    - client auth
  secretName: harbor-core-internal-tls
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: harbor-jobservice-internal-tls
spec:
  issuerRef:
    group: cert-manager.io
    kind: Issuer
    name: internal-tls-issuer
  commonName: harbor-jobservice
  dnsNames:
    - harbor-jobservice
  usages:
    - server auth
    - client auth
  secretName: harbor-jobservice-internal-tls
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: harbor-registry-internal-tls
spec:
  issuerRef:
    group: cert-manager.io
    kind: Issuer
    name: internal-tls-issuer
  commonName: harbor-registry
  dnsNames:
    - harbor-registry
  usages:
    - server auth
    - client auth
  secretName: harbor-registry-internal-tls
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: harbor-portal-internal-tls
spec:
  issuerRef:
    group: cert-manager.io
    kind: Issuer
    name: internal-tls-issuer
  commonName: harbor-portal
  dnsNames:
    - harbor-portal
  usages:
    - server auth
    - client auth
  secretName: harbor-portal-internal-tls
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: harbor-trivy-internal-tls
spec:
  issuerRef:
    group: cert-manager.io
    kind: Issuer
    name: internal-tls-issuer
  commonName: harbor-trivy
  dnsNames:
    - harbor-trivy
  usages:
    - server auth
    - client auth
  secretName: harbor-trivy-internal-tls

It generally works, components can communicate with each other, Portal is operational etc etc. But pulling public images or logging in with docker login do not work (note that in the currently released version i.e. v2.10.0 there is a separate issue https://github.com/goharbor/harbor/issues/20080 which makes symptoms entirely different, core returns 200 response with an empty token; this is what I get with my patch from https://github.com/goharbor/harbor/pull/20081):

> nerdctl pull harbor.example.com/hub.docker.com/jenkins/jenkins:lts
harbor.example.com/hub.docker.com/jenkins/jenkins:lts: resolving      |--------------------------------------|
elapsed: 2.4 s                                                            total:   0.0 B (0.0 B/s)
INFO[0002] trying next host                              error="failed to authorize: failed to fetch anonymous token: unexpected status from GET request to https://harbor.example.com/service/token?scope=repository%3Ahub.docker.com%2Fjenkins%2Fjenkins%3Apull&service=harbor-registry: 500 Internal Server Error" host=harbor.example.com
FATA[0002] failed to resolve reference "harbor.example.com/hub.docker.com/jenkins/jenkins:lts": failed to authorize: failed to fetch anonymous token: unexpected status from GET request to https://harbor.example.com/service/token?scope=repository%3Ahub.docker.com%2Fjenkins%2Fjenkins%3Apull&service=harbor-registry: 500 Internal Server Error
Error: exit status 1

Core logs ():

2024-03-03T22:45:39Z [ERROR] [/core/service/token/token.go:50]: Unexpected error when creating the token, error: x509: failed to parse private key (use ParseECPrivateKey instead for this key format)

Steps to reproduce the problem:

Try to pull public image or log in to Harbor using ECDSA certificate as internal tls CA.

Versions: Please specify the versions of following systems.

Additional context:

Slack thread: https://cloud-native.slack.com/archives/CC1E09J6S/p1709497679881159

MinerYang commented 3 months ago

We are stetting RSA256 as default signed methods https://github.com/goharbor/harbor/blob/d25f3556a94a687d58faeac1197dd5090b17ec29/src/core/service/token/authutils.go#L114 And errors occurs when using ParseRSAPrivateKeyFromPEM to passe the ECDSA signed private key https://github.com/goharbor/harbor/blob/d25f3556a94a687d58faeac1197dd5090b17ec29/src/pkg/token/options.go#L48C12-L48C28

dee-kryvenko commented 3 months ago

Hmmm looks easy enough. Would you be interested in a PR?

MinerYang commented 3 months ago

Sure , we would like to consider this as a requirement. To enable this we need expose key signed method and change the default options properly. Probably not the common case for most of the users. Could you help me to learn the necessity of configure this algorithm?

dee-kryvenko commented 3 months ago

This is just my default choice over RSA and I recon it will be more common into the future. I am wondering that the code could detect the type of certificate automatically without user input, even if through try-fail-retry...

MinerYang commented 3 months ago

True, will look into this and evaluate if there's any other impact ...