Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does this crate support self signed certificates #24

Open
elliot-ast opened this issue Jun 12, 2024 · 5 comments
Open

Does this crate support self signed certificates #24

elliot-ast opened this issue Jun 12, 2024 · 5 comments

Comments

@elliot-ast
Copy link

Hello does this crate support self signed certificates. I've gotten this to crate to work when I didn't have TLS on my keycloak server but adding TLS support with following command I can't get this crate to work 🤷‍♂️

docker run -p 8443:8443   
-e KC_HTTPS_CERTIFICATE_FILE=/etc/x509/https/tls.crt 
-e KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/x509/https/tls.key  
-e KC_HTTPS_PORT=8443  
-e KC_HTTP_ENABLED=false  
-e KEYCLOAK_ADMIN=admin   
-e KEYCLOAK_ADMIN_PASSWORD=admin  
 -v /self_signed_certs/localhostCert.pem:/etc/x509/https/tls.crt 
 -v /self_signed_certs/localhostKey.pem:/etc/x509/https/tls.key   
quay.io/keycloak/keycloak:24.0.5  start-dev --https-port=8443

were the certificates are created via

openssl req -x509 -out localhostCert.pem. -keyout localhostKey.pem \
  -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=localhost' -extensions EXT -config <( \
   printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

and running the standard code from this crate and Axum TLS example where the realm is swapped realm to myrealm instead where there's a user with the realm role administrator. From my JWT

 "allowed-origins": [
    "https://127.0.0.1:3000"
  ],
  "realm_access": {
    "roles": [
      "administrator",
      "default-roles-myapi",
      "offline_access",
      "uma_authorization"
    ]
  }, 

This is the rust code used

[tokio::main]
async fn main() {
    let ports = Ports {
        http: 7878,
        https: 3000,
    };
    // optional: spawn a second server to redirect http requests to this server
    tokio::spawn(redirect_http_to_https(ports));

    // configure certificate and private key used by https
    let config = RustlsConfig::from_pem_file(
        PathBuf::from(env!("CARGO_MANIFEST_DIR"))
            .join("self_signed_certs")
            .join("localhostCert.pem"),
        PathBuf::from(env!("CARGO_MANIFEST_DIR"))
            .join("self_signed_certs")
            .join("localhostKey.pem"),
    )
    .await
    .unwrap();

    let keycloak_auth_instance = KeycloakAuthInstance::new(
        KeycloakConfig::builder()
            .server(Url::parse("https://127.0.0.1:8443/").unwrap())
            .realm(String::from("myapi"))
            .build(),
    );
    let app = public_router().merge(protected_router(keycloak_auth_instance));
    let addr = SocketAddr::from(([127, 0, 0, 1], ports.https));
    tracing::debug!("listening on {}", addr);
    axum_server::bind_rustls(addr, config)
        .serve(app.into_make_service())
        .await
        .unwrap();
} 

I don't know what is causing this

curl -k https://127.0.0.1:3000/protected -H "Authorization: Bearer $(cat JWT.txt)" 

gives me the output

{"error":"There were no decoding keys available."}

Is this an issue with my keycloak setup or is it this crate that's not supporting self signed certs?

@Tockra
Copy link
Contributor

Tockra commented Jun 12, 2024

Maybe you should access your server with the URL you set at your CN.
So don't call 127.0.0.1. Instead use "localhost" or sign a new certifcate with CN 127.0.0.1 .
I had this problem in a lot of librarys using SSL/TLS.
Sometimes even the CN was not enough. Then the library ignored it and wanted a set SAN : https://support.dnsimple.com/articles/what-is-ssl-san/

Maybe this could already solute your problem.
If not, pleas provide some logging of your application. What does it show while it can not access your keycloaks public key?

@elliot-ast
Copy link
Author

Alright thanks for looking into this, I've tried to generate the pem files with openssl.cnf file instead with

openssl req -x509 -out localhostCert.pem -keyout localhostKey.pem \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=localhost' -extensions EXT -config openssl.cnf

where my config looks like

[ req ]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext
x509_extensions = v3_ca

[ dn ]
CN = localhost

[ req_ext ]
subjectAltName = @alt_names

[ v3_ca ]
subjectAltName = @alt_names
keyUsage = digitalSignature, keyCertSign, cRLSign
basicConstraints = CA:TRUE

[ alt_names ]
DNS.1 = localhost
IP.1 = 127.0.0.1

the issue persist even though I've altered everything in the rust files to use localhost instead of the 127.0.0.1 this is probably not an issue with this crate and I guess it would work when using signed certificates. Unless there is some setting I need to enable in keycloak?

Not sure what kind of logging you want from the keycloak/rust app that I can provide you with could you elaborate on this?

@Tockra
Copy link
Contributor

Tockra commented Jun 12, 2024

If I include the middleware into my application and setup a logging crate like fern I'll get a lot of debug messages when I run my application:
e.g. execute the following function in the top of your main function.

pub fn setup_logger() -> Result<(), fern::InitError> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "[{} {} {}] {}",
                humantime::format_rfc3339_seconds(SystemTime::now()),
                record.level(),
                record.target(),
                message
            ))
        })
        .level(log::LevelFilter::Debug)
        .chain(std::io::stdout())
        .chain(fern::log_file("output.log")?)
        .apply()?;
    Ok(())
}

https://crates.io/crates/fern

[...]
[2024-06-12T09:58:12Z DEBUG hyper_util::client::legacy::connect::http] connecting to [::1]:8888
[2024-06-12T09:58:12Z DEBUG hyper_util::client::legacy::connect::http] connected to [::1]:8888
[2024-06-12T09:58:13Z DEBUG hyper_util::client::legacy::pool] pooling idle connection for ("http", localhost:8888)
[2024-06-12T09:58:13Z DEBUG try_again] retry_async; retry_strategy=Retry { max_tries: 5, delay: Some(Static { delay: 1s }) } delay_strategy=TokioSleep
[2024-06-12T09:58:13Z DEBUG reqwest::connect] starting new connection: http://localhost:8888/
[2024-06-12T09:58:13Z DEBUG hyper_util::client::legacy::connect::dns] resolving host="localhost"
[2024-06-12T09:58:13Z DEBUG hyper_util::client::legacy::connect::http] connecting to [::1]:8888
[2024-06-12T09:58:13Z DEBUG hyper_util::client::legacy::connect::http] connected to [::1]:8888
[2024-06-12T09:58:13Z DEBUG hyper_util::client::legacy::pool] pooling idle connection for ("http", localhost:8888)
[2024-06-12T09:58:13Z INFO axum_keycloak_auth::instance] Received new jwk_set containing 2 keys.
[...]

Here you should/could see a error message, if your application is not able to receive the public key from your keycloak server.

The above example is just a example. You don't have to use fern. I'm pretty sure you can use any crate listed here https://crates.io/crates/log under "In executables"

@elliot-ast
Copy link
Author

Alright great thanks for the help on logging! So the reason seems to be because of self signed certificates as this seems to be what is causing the response

[2024-06-12T10:21:26Z INFO axum_keycloak_auth::instance] Starting OIDC discovery.
[2024-06-12T10:21:26Z DEBUG try_again] retry_async; retry_strategy=Retry { max_tries: 5, delay: Some(Static { delay: 1s }) } delay_strategy=TokioSleep
[2024-06-12T10:21:26Z DEBUG reqwest::connect] starting new connection: https://localhost:8443/
[2024-06-12T10:21:26Z DEBUG h2::codec::framed_read] received frame=Settings { flags: (0x1: ACK) }
[2024-06-12T10:21:26Z DEBUG h2::proto::settings] received settings ACK; applying Settings { flags: (0x0), max_concurrent_streams: 200, initial_window_size: 1048576, max_frame_size: 16384, max_header_list_size: 16384 }
[2024-06-12T10:21:26Z DEBUG hyper::client::connect::dns] resolving host="localhost"
[2024-06-12T10:21:26Z DEBUG hyper::client::connect::http] connecting to 127.0.0.1:8443
[2024-06-12T10:21:26Z DEBUG hyper::client::connect::http] connected to 127.0.0.1:8443
[2024-06-12T10:21:26Z DEBUG try_again] Operation was not successful. Waiting... tries=1 delay=1s
[2024-06-12T10:21:27Z DEBUG reqwest::connect] starting new connection: https://localhost:8443/
[2024-06-12T10:21:27Z DEBUG hyper::client::connect::dns] resolving host="localhost"
[2024-06-12T10:21:27Z DEBUG hyper::client::connect::http] connecting to 127.0.0.1:8443
[2024-06-12T10:21:27Z DEBUG hyper::client::connect::http] connected to 127.0.0.1:8443
[2024-06-12T10:21:27Z DEBUG try_again] Operation was not successful. Waiting... tries=2 delay=1s
[2024-06-12T10:21:28Z DEBUG reqwest::connect] starting new connection: https://localhost:8443/
[2024-06-12T10:21:28Z DEBUG hyper::client::connect::dns] resolving host="localhost"
[2024-06-12T10:21:28Z DEBUG hyper::client::connect::http] connecting to 127.0.0.1:8443
[2024-06-12T10:21:28Z DEBUG hyper::client::connect::http] connected to 127.0.0.1:8443
[2024-06-12T10:21:28Z DEBUG try_again] Operation was not successful. Waiting... tries=3 delay=1s
[2024-06-12T10:21:29Z DEBUG reqwest::connect] starting new connection: https://localhost:8443/
[2024-06-12T10:21:29Z DEBUG hyper::client::connect::dns] resolving host="localhost"
[2024-06-12T10:21:29Z DEBUG hyper::client::connect::http] connecting to 127.0.0.1:8443
[2024-06-12T10:21:29Z DEBUG hyper::client::connect::http] connected to 127.0.0.1:8443
[2024-06-12T10:21:29Z DEBUG try_again] Operation was not successful. Waiting... tries=4 delay=1s
[2024-06-12T10:21:30Z DEBUG reqwest::connect] starting new connection: https://localhost:8443/
[2024-06-12T10:21:30Z DEBUG hyper::client::connect::dns] resolving host="localhost"
[2024-06-12T10:21:30Z DEBUG hyper::client::connect::http] connecting to 127.0.0.1:8443
[2024-06-12T10:21:30Z DEBUG hyper::client::connect::http] connected to 127.0.0.1:8443

[2024-06-12T10:21:30Z ERROR try_again] Operation was not successful after maximum retries. Aborting with last output seen. tries=5 last_output=Err(OidcDiscovery { source: Send { source: reqwest::Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("localhost")), port: Some(8443), path: "/realms/myapi/.well-known/openid-configuration", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167772294, library: "SSL routines", function: "tls_post_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1883 }]))) }, X509VerifyResult { code: 18, error: "self-signed certificate" })) } } })

[2024-06-12T10:21:30Z ERROR axum_keycloak_auth::instance] Could not retrieve OIDC config. err="Could not discover OIDC configuration.\n\nCaused by these errors (recent errors listed first):\n  1: RequestError: Could not send request\n  2: error sending request for url (https://localhost:8443/realms/myapi/.well-known/openid-configuration) *\n  3: error trying to connect *\n  4: error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:../ssl/statem/statem_clnt.c:1883: (self-signed certificate)\n  5: error:0A000086:SSL routines:tls_post_process_server_certificate:certificate verify failed:../ssl/statem/statem_clnt.c:1883:\n\nNOTE: Some redundant information has been removed from the lines marked with *. Set SNAFU_RAW_ERROR_MESSAGES=1 to disable this behavior.\n"
[2024-06-12T10:21:30Z DEBUG h2::codec::framed_write] send frame=Headers { stream_id: StreamId(1), flags: (0x4: END_HEADERS) }
[2024-06-12T10:21:30Z DEBUG h2::codec::framed_write] send frame=Data { stream_id: StreamId(1), flags: (0x1: END_STREAM) }
[2024-06-12T10:21:30Z DEBUG rustls::common_state] Sending warning alert CloseNotify
:Error { kind: Request, url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("localhost")), port: Some(8443), path: "/realms/myapi/.well-known/openid-configuration", query: None, fragment: None }, source: hyper::Error(Connect, Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167772294, library: "SSL routines", function: "tls_post_process_server_certificate", reason: "certificate verify failed", file: "../ssl/statem/statem_clnt.c", line: 1883 }]))) }, X509VerifyResult { code: 18, error: "self-signed certificate" })) } } })

@lpotthast
Copy link
Owner

Hmm, your issue shouldn't be related to the implementation of this library.

I have such a setup running and working fine. I would guess that it's simply related to how the certificates are created / set up. Two things come to mind:

  • Did you add the certificate authority (CA), which you used to create your self-signed-certificate, to your OS?
  • I always use rustls. Are you doing the same?

Cannot think of any differences in code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants