# Avoid passing `--plain-http` when `--insecure` specified in oras
When using ORAS to access plain-HTTP registry service, users need to specify `--plain-http`. ORAS CLI should be able to do automatic https-to-http handling via specifying `--insecure` and remove `--plain-http` flag. The detailed proposal and discussion are tracked in https://github.com/oras-project/oras/issues/914
This doc demonstrates the new experience of using `--insecure` flag and how automatic https-to-http handling in ORAS CLI. However, there are some edge cases for ORAS when the registry has local DNS configured using the ORAS flag `--resolve`. This doc also outlines this edge case and provides some options for open discussion. We will need to determine an appropriate experience from the given options.
This doc also outlines the behaviors of other popular registry clients when interacting with insecure registries.
## Automatic https-to-http handling in ORAS CLI
If ORAS CLI is changed to provide an `--insecure` flag with automatic https-to-http fallback, the low level implementation should look like below:
```mermaid
sequenceDiagram
participant A as oras
participant B as registry(HTTP)
rect rgb(191, 223, 255)
A->>B: TLS handshake
B-->>A: RecordHeader "HTTP/"
A->>B:HTTP
end
Note over A,B: HTTP over TCP connection...
```
Related PR: https://github.com/oras-project/oras/pull/920
## Working with customized DNS resolution
Let's say we are going to use oras to access a HTTP registry service, `my.test.registry` which is running locally(0.0.0.0) at port 5000
### Option 1: setup a DNS file
User can setup a HOSTS file to hard-code DNS in a system level:
```shell
oras login my.test.registry:5000 --insecure
```
```mermaid
sequenceDiagram
participant A as oras
participant D as HOSTS File
participant B as 0.0.0.0:5000(HTTP)
A->>D: match IP for my.test.registry
D->>A: 0.0.0.0
rect rgb(191, 223, 255)
A->>B: TLS handshake
B-->>A: error + recordHeader="HTTP/"
A->>B:HTTP
end
Note over A,B: HTTP over TCP connection...
```
This works fine with the UX of https->http auto handling via `--insecure`.
### Option 2: use `--resolve` without port redirection
Sometimes users don't want to setup such a system-wide DNS rule. To customize the DNS resolution within command execution, user can use`--resolve host:port:address`, representing below endpoint mapping:
```mermaid
flowchart LR
A["host:port"] -->B["address:port"]
```
Below is an example of using it to log in to the registry `my.test.registry:5000`
```shell
oras login my.test.registry:5000\
--resolve my.test.registry:5000:0.0.0.0\
--insecure
```
```mermaid
sequenceDiagram
participant A as oras
participant B as 0.0.0.0:5000(HTTP)
participant C as resolve rules
A->>C: match endpoint for my.test.registry:5000
C-->>A: 0.0.0.0:5000
rect rgb(191, 223, 255)
A->>B: TLS handshake
B-->>A: RecordHeader "HTTP/"
A->>B:HTTP
end
Note over A,B: HTTP over TCP connection...
```
### Option 3: use `--resolve` with port redirection
#### why we need port redirection
Sometimes user cannot add port in the registry name, e.g. `my.registy.com` and `my.registry.com:5000` can be used to run two different registry services.
Suppose below command is used to login to a locally running HTTP registry at port `5000`
```console
oras login my.test.registry\
--resolve my.test.registry:5000:0.0.0.0\
--insecure
```
The DNS resolution will fail since `my.test.registry:443` is not covered by the customized DNS rule:
```mermaid
sequenceDiagram
participant A as oras
participant C as resolve rules
participant B as DNS
participant E as my.test.registry:443
participant D as 0.0.0.0:5000(HTTP)
A->>C: match endpoint for my.test.registry:443
C-->>A: not found
A->>B: query IP for my.test.registry
B-->>A: 20.14.194.49
A->>E: TLS handshake
Note over A,E: ...
```
#### https-to-http automatic handling with port redirection
Introduced by ORAS, flag `--resolve host:port:address:address_port` represents:
```mermaid
flowchart LR
A["host:port"] -->B["address:address_port"]
```
With port redirection, ORAS users can
```bash
oras login my.test.registry \
--resolve my.test.registry:443:0.0.0.0:5000 \
--resolve my.test.registry:80:0.0.0.0:5000 \
--insecure
```
The UX is quite verbose since both `443` and `80` rules are required to be specified:
```mermaid
sequenceDiagram
participant A as oras
participant C as resolve rules
participant D as 0.0.0.0:5000(HTTP)
A->>C: match endpoint for my.test.registry:443
C-->>A: 0.0.0.0:5000
rect rgb(191, 223, 255)
A->>D:TLS handshake
D-->>A: RecordHeader "HTTP/"
A->>C: match endpoint for my.test.registry:80
C-->>A: 0.0.0.0:5000
A->>D: HTTP
end
Note over A,D: HTTP over TCP connection...
```
## What If
- users want to access a registry with expired https cert
This use case doesn't include https->http handling, user can simply use `--insecure`, like:
```bash
oras login my.test.registry --insecure
```
- users need to login insecurely to a HTTP registry with customized DNS and **pull image without port**
This is really an edge case but indeed, using `--plain-http` is much more simpler than HTTP auto fallback with`--insecure`
```bash
oras login my.test.registry \
--resolve my.test.registry:443:0.0.0.0:5000 \
--resolve my.test.registry:80:0.0.0.0:5000 \
--insecure
# or
oras login my.test.registry \
--resolve my.test.registry:5000:0.0.0.0 \
--plain-http
```
- users need to login insecurely to a HTTP registry without port in the registry host name & custom HTTPS DNS rule is not specified
Will fail because `my.test.registry:443` is not covered. Traffic will lands on remote registry(if it exists) instead of `0.0.0.0:5000`:
```bash
oras login my.test.registry \
--resolve my.test.registry:80:0.0.0.0:5000 \
--insecure
```
```mermaid
sequenceDiagram
participant A as oras
participant C as resolve rules
participant B as DNS
participant E as my.test.registry:443
participant D as 0.0.0.0:5000(HTTP)
A->>C: match endpoint for my.test.registry:443
C-->>A: not found
A->>B: query IP for my.test.registry
B-->>A: 20.14.194.49
A->>E: TLS handshake
Note over A,E: HTTP over TCP connection...
```
- users need to login insecurely to a HTTP registry without port in the registry host name, HTTPS token service is running remotely
Will fail, not supported
## Compare the user experience in other registry clients
After investigated other registry clients like Docker, Skopeo, ctr, they provide automatic HTTPS->HTTP handling:
- docker: user can mark a registry as insecure [in the configuration file](https://docs.docker.com/registry/insecure/#deploy-a-plain-http-registry). With insecure registries enabled, Docker goes through the following steps:
- try using HTTPS.
- If HTTPS is available but the certificate is invalid, ignore the error about the certificate.
- If HTTPS is not available, fall back to HTTP.
- skopeo: docker-like UX via flag`--tls-verify`, implementation based on mocked [configuration](https://github.com/containers/image/blob/main/docker/docker_client.go#L817)
- containerd/nerdctl: docker-like UX via flag `--insecure-registry` ([fallback code](https://github.com/containerd/nerdctl/blob/main/pkg/imgutil/imgutil.go#L148))
The ctr CLI requires user to specify whether a remote registry supports TLS explicitly(this is currently ORAS' UX):
- containerd/ctr: has specific flags for using plain HTTP `--plain-http` and skipping TLS check `--skip-verify/-k`