kubevirt / containerized-data-importer

Data Import Service for kubernetes, designed with kubevirt in mind.
Apache License 2.0
426 stars 267 forks source link

expected status code 200, got 401. Status: 401 Unauthorized #3527

Open Gops123 opened 2 days ago

Gops123 commented 2 days ago

What happened: A Kubernetes Secret is used to securely pass credentials for accessing the Artifactory repository. The DataVolume configuration references this Secret for authentication to pull the image. The URL for the image source is specified within the DataVolume configuration, with artifact-repo-credentials providing the necessary accessKeyId and secretKey for access. credentials are correct but still seeing a 401 Unauthorized error

k logs importer-prime-4c45f9a2-160b-45dd-b91d-d3a7277b1842 
I1112 11:26:08.283400       1 importer.go:107] Starting importer
I1112 11:26:08.283455       1 importer.go:182] begin import process
E1112 11:26:08.362389       1 http-datasource.go:429] http: expected status code 200, got 401
E1112 11:26:08.377798       1 http-datasource.go:353] http: expected status code 200, got 401
E1112 11:26:08.377876       1 importer.go:347] expected status code 200, got 401. Status: 401 Unauthorized
kubevirt.io/containerized-data-importer/pkg/importer.createHTTPReader
    pkg/importer/http-datasource.go:354
kubevirt.io/containerized-data-importer/pkg/importer.NewHTTPDataSource
    pkg/importer/http-datasource.go:102
main.newDataSource
    cmd/cdi-importer/importer.go:272
main.handleImport
    cmd/cdi-importer/importer.go:184
main.main
    cmd/cdi-importer/importer.go:148
runtime.main
    GOROOT/src/runtime/proc.go:271
runtime.goexit
    src/runtime/asm_amd64.s:1695 

What you expected to happen: A clear and concise description of what you expected to happen.

Additional context: Add any other context about the problem here.

Environment:

apiVersion: v1
kind: Secret
metadata:
  name: credentials
type: Opaque
data:
  accessKeyId: <base64>
  secretKey: <base64>
---
apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
  metadata:
    name: artifact-repo-dv
spec:
  pvc:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 100Gi
    storageClassName: gp3
  source:
    http:
      url: "https://artifact.in/artifactory/windows-images/win2019/windows.iso"
      secretRef: credentials 
akalenyu commented 2 days ago

Hey, thanks for reporting. What's the curl equivalent command (with secrets omitted, ofc) that succesfully pulls the image from the artifactory?

Also make sure you're not accidentally encoding \n in the id/key.

Gops123 commented 2 days ago

Hello, I'm using the following curl command to download an image:

curl -u "username:password" -O "https://artifact.in/artifactory/windows-images/win2019/windows.iso"

The command works independently, but it’s not working as expected within the above manifest. I’ve verified that there are no \n characters in the username or password.

akalenyu commented 2 days ago

Interesting.. this is precisely what CDI is doing https://github.com/kubevirt/containerized-data-importer/blob/c15ad1d5c12f572a8208dea35c6b045c52bdf7f1/pkg/importer/http-datasource.go#L345 Do you have access to the artifactory side, to check the logs there?

Gops123 commented 2 days ago

No I don't have access to artifactory to check logs

akalenyu commented 2 days ago

Okay, could you try executing this curl command from inside a pod in the cluster, in the same ns? similarly to what the cdi-importer is doing?

Gops123 commented 2 days ago

curl working from pod

> User-Agent: curl/8.5.0
> Accept: */*
>
{ [5 bytes data]
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Disposition: attachment; filename="win.iso"; filename*=UTF-8''win.iso
< Content-Type: application/octet-stream
< Date: Wed, 13 Nov 2024 13:00:02 GMT
akalenyu commented 2 days ago

curl working from pod

> User-Agent: curl/8.5.0
> Accept: */*
>
{ [5 bytes data]
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Disposition: attachment; filename="win.iso"; filename*=UTF-8''win.iso
< Content-Type: application/octet-stream
< Date: Wed, 13 Nov 2024 13:00:02 GMT

curl -vvv may help spot the differences between curl/importer application, just make sure to leave out the credentials

Gops123 commented 2 days ago

Hello @akalenyu here is the required output from curl with verbose


* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.2 (IN), TLS header, Certificate Status (22):
{ [5 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [89 bytes data]
* TLSv1.2 (IN), TLS header, Certificate Status (22):
{ [5 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4304 bytes data]
* TLSv1.2 (IN), TLS header, Certificate Status (22):
{ [5 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [333 bytes data]
* TLSv1.2 (IN), TLS header, Certificate Status (22):
{ [5 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [70 bytes data]
* TLSv1.2 (OUT), TLS header, Finished (20):
} [5 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS header, Finished (20):
{ [5 bytes data]
* TLSv1.2 (IN), TLS header, Certificate Status (22):
{ [5 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=aaaaa Inc.; CN=artifactory.com
*  start date: Dec 12 00:00:00 2023 GMT
*  expire date: Jan 11 23:59:59 2025 GMT
*  subjectAltName: host "artifactory.com" matched cert's "artifactory.com"
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert TLS RSA SHA256 2020 CA1
*  SSL certificate verify ok.
* Server auth using Basic with user 'xxxxx'
* TLSv1.2 (OUT), TLS header, Unknown (23):
} [5 bytes data]
> GET artifactory/windows-images/win2019/windows.iso HTTP/1.1
> Host: artifactory.com
> Authorization: Basic xxxxxx
> User-Agent: curl/7.76.1
> Accept: */*
>
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* TLSv1.2 (IN), TLS header, Unknown (23):
{ [5 bytes data]
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Disposition: attachment; filename="windows.iso"; filename*=UTF-8''windows.iso
< Content-Type: application/octet-stream
< Date: Wed, 13 Nov 2024 13:41:24 GMT
< ETag: 3402039abb970b3cd851
< Last-Modified: Tue, 12 Nov 2024 09:33:19 GMT
< X-Artifactory-Filename: windows.iso
< X-Artifactory-Id: 62879b11ca5dffd7296b1500c27db7
< X-Artifactory-Node-Id: uw2010012
< X-Checksum-Md5: 8f9a70435dc5b0b86cf
< X-Checksum-Sha1: 3402039abb970b3cd851efc
< X-Checksum-Sha256: 55c687a9a242fab7b0ec89ac69f9def
< X-JFrog-Version: Artifactory/7.63.22 76322900
< Content-Length: 65366
< Connection: keep-alive ```
akalenyu commented 2 days ago

This looks like the exact same thing CDI is doing. You could try to write a simple golang program that tries to pull from the artifactory, with your credentials, I expect that it would fail with the golang http client

Gops123 commented 2 days ago

yes tried and getting expected status code

akalenyu commented 2 days ago

yes tried and getting expected status code

Cool, so you can try spotting the bug, I believe it would be somewhere in https://github.com/kubevirt/containerized-data-importer/blob/c15ad1d5c12f572a8208dea35c6b045c52bdf7f1/pkg/importer/http-datasource.go

Gops123 commented 6 hours ago

Encountering an issue where extra newline characters (\n) are getting appended to accessKey and secKey in the createHTTPReader function. https://github.com/kubevirt/containerized-data-importer/blob/main/pkg/importer/http-datasource.go#L317

awels commented 6 hours ago

When you created the secret with the accessKeyId and secretKey you had to base64 encode the username and password. Make sure that when you do this the base64 encoded value doesn't include the \n for instance echo -n "password" | base64 should encode without encoding the \n check the output with and without the -n on the echo and compare it to the value in the secret.