Giter Club home page Giter Club logo

rustls-acme's People

Contributors

10ne1 avatar florianuekermann avatar joshtriplett avatar kraigher avatar ludea avatar mkj avatar soenkehahn avatar tyjvazum avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rustls-acme's Issues

Error after upgrading rustls-acme to 0.8 and rustls to 0.22

I upgraded rustls-acme to 0.8 and rustls to 0.22, but I'm getting a compiler error.

error[E0432]: unresolved import rustls
--> /home/t/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rustls-acme-0.8.0/src/axum.rs:4:5
|
4 | use rustls::ServerConfig;
| ^^^^^^ help: a similar path exists: futures_rustls::rustls

error[E0433]: failed to resolve: use of undeclared crate or module rustls
--> /home/t/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rustls-acme-0.8.0/src/state.rs:134:52
|
134 | pub fn axum_acceptor(&self, rustls_config: Arcrustls::ServerConfig) -> crate::axum::AxumAcceptor {
| ^^^^^^ use of undeclared crate or module rustls
|
help: consider importing one of these items
|
1 + use crate::futures_rustls::rustls;
|
1 + use futures_rustls::rustls;

Testing in challenging

I'm not sure what the solution is, but writing tests against a server that uses rustls-acme is rather challenging. Our dev and CI machines don't have public-facing domains, which precludes requesting certs from let's encrypt. Also, even if we could, this would slow down the tests.

One possible solution would be to allow injecting a cert into an AcmeConfig, which would be used in testing instead of contacting Let's Encrypt for a cert.

Compatibility with tokio-based warp library

First of all: thank you for this nice library with a well though-out interface. I would really like to use it within a project using the tokio-based warp library (https://docs.rs/warp/). The problem I run into is that this library only supports running on a stream of incoming connections (https://docs.rs/warp/latest/warp/struct.Server.html#method.run_incoming) with trait bounds for tokio::io::{AsyncRead,AsyncWrite}. I can't use a custom acceptor like in the high_level_tokio example to run the compat() method, so I'm stuck for now.

Example of the code I have so far:

use tokio::{ fs, sync, net::TcpListener };
use tokio_stream::wrappers::TcpListenerStream;
use tokio_util::compat::TokioAsyncReadCompatExt;
use futures_util::stream::{ StreamExt, TryStreamExt };
use rustls_acme::{ AcmeConfig, caches::DirCache };

tokio::spawn(async move {
    let tcp_listener = TcpListener::bind(sa).await.unwrap();
    let tcp_incoming = TryStreamExt::map_ok(TcpListenerStream::new(tcp_listener), |tcp_stream| { tcp_stream.compat() });
    let mut tls_incoming = AcmeConfig::new(["example.com"])
        .contact_push("mailto:[email protected]")
        .cache(DirCache::new("./tmp"))
        .incoming(tcp_incoming);
    let index = warp::path::end().map(|| warp::reply::html(INDEX_FILE));
    warp::serve(index).run_incoming(tls_incoming).await;
});

This fails to compile with:

the trait bound `rustls_acme::futures_rustls::server::TlsStream<Compat<tokio::net::TcpStream>>: tokio::io::AsyncRead` is not satisfied

If I change the last line to:

warp::serve(index).run_incoming(tls_incoming.compat()).await;

I get:

error[E0599]: the method `compat` exists for struct `rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>`, but its trait bounds were not satisfied
   --> src/control.rs:226:81
    |
226 |               warp::serve(index.or(icon).or(websocket)).run_incoming(tls_incoming.compat()).await;
    |                                                                                   ^^^^^^ method cannot be called on `rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>` due to unsatisfied trait bounds
    |
   ::: /home/sargeth/.cargo/registry/src/github.com-1ecc6299db9ec823/rustls-acme-0.5.1/src/incoming.rs:13:1
    |
13  | / pub struct Incoming<
14  | |     TCP: AsyncRead + AsyncWrite + Unpin,
15  | |     ETCP,
16  | |     ITCP: Stream<Item = Result<TCP, ETCP>> + Unpin,
...   |
25  | |     tls_accepting: FuturesUnordered<Accept<TCP>>,
26  | | }
    | | -
    | | |
    | |_doesn't satisfy `_: TokioAsyncReadCompatExt`
    |   doesn't satisfy `_: tokio::io::AsyncRead`
    |
    = note: the following trait bounds were not satisfied:
            `rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>: tokio::io::AsyncRead`
            which is required by `rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>: TokioAsyncReadCompatExt`
            `&rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>: tokio::io::AsyncRead`
            which is required by `&rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>: TokioAsyncReadCompatExt`
            `&mut rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>: tokio::io::AsyncRead`
            which is required by `&mut rustls_acme::Incoming<Compat<tokio::net::TcpStream>, std::io::Error, futures_util::stream::MapOk<TcpListenerStream, [closure@src/control.rs:212:91: 212:127]>, std::io::Error, std::io::Error>: TokioAsyncReadCompatExt`

I'm not sure this can be solved reasonably within this library, but wanted to reach out just in case. Superficially it seems to me to be similar to the problem that came up with axum (#27), but it might be more complicated.

Add an optional `tonic` feature with tonic compatibility helpers?

We're using rustls-acme with tonic, and so far we wrote a some boilerplatey code to hook up rustls-acme to Tonic's batteries-included server implementation.

If we extracted that code and submitted a PR, would you be interested in upstreaming it under a feature flag?

I'm imagining implementing an extension trait, say AcmeTonicExt, so that instead of writing

Server::builder()
    .add_service(/* ... */)
    .add_service(/* ... */)
    .serve(addr)

for an http server, it would be possible to write

Server::builder()
    .add_service(/* ... */)
    .add_service(/* ... */)
    .serve_with_acme_tls(addr, acme_config)

for an auto-https server. The serve_with_acme_tls method would be provided by the extension trait, and handle gluing the rustls-acme methods to the tonic serve_with_incoming method.

Certificates not renewing

I have rustls-acme managing the certs for ordinals.com, and they aren't being renewed despite the expiration date being a couple weeks away:

$ openssl s_client -servername ordinals.com -connect ordinals.com:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Aug 23 05:54:45 2022 GMT
notAfter=Nov 21 05:54:44 2022 GMT

On restart, the logs display the following:

Nov 09 16:34:14 ordinals.com ord[1386831]: [2022-11-09T16:34:14Z INFO  ord::subcommand::server] ACME event: DeployedCachedCert

Am I understanding the output correctly? And is there anything I need to do to get the certs to renew?

Unclear how to combine with `hyper`'s getting started guide

During my CS master, one teacher always said that if something is unclear to me, I should ask since it is likely unclear to other people too. I hope it's okay to ask here too.

I've setup a server with hyper's getting started guide (https://hyper.rs/guides/1/server/hello-world/):

use std::convert::Infallible;
use std::net::SocketAddr;

use http_body_util::Full;
use hyper::body::Bytes;
use hyper::server::conn::http1;
use hyper::service::service_fn;
use hyper::{Request, Response};
use hyper_util::rt::TokioIo;
use tokio::net::TcpListener;

async fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
    Ok(Response::new(Full::new(Bytes::from("Hello, World!"))))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    // We create a TcpListener and bind it to 127.0.0.1:3000
    let listener = TcpListener::bind(addr).await?;

    // We start a loop to continuously accept incoming connections
    loop {
        let (stream, _) = listener.accept().await?;

        // Use an adapter to access something implementing `tokio::io` traits as if they implement
        // `hyper::rt` IO traits.
        let io = TokioIo::new(stream);

        // Spawn a tokio task to serve multiple connections concurrently
        tokio::task::spawn(async move {
            // Finally, we bind the incoming connection to our `hello` service
            if let Err(err) = http1::Builder::new()
                // `service_fn` converts our function in a `Service`
                .serve_connection(io, service_fn(hello))
                .await
            {
                eprintln!("Error serving connection: {:?}", err);
            }
        });
    }
}

This worked fine for me, but I have so far been unable to integrate rustls-acme into it. The current examples/high_level_tokio.rs uses TcpListenerStream and next() instead of listener.accept(). Would it be a good idea for a hyper example to be added?

As a side-note, at some point I had something working but then curl responded with

curl: (1) Received HTTP/0.9 when not allowed

which is a weird issue, I think. I'm using all the latest versions according to

cargo outdated --depth=1

Bump to rustls 0.23

Hello!

Simple bumping futures-rustls doesn't work since your custom async-web-client is still also on rustls-0.22 and client-config cannot be passed to it.

  1. Bump async-web-client also to newer version
  2. Switch to reqwest as an HTTP client instead to have one less crate to worry about?

I think (2) is nicer, I can do a PR if needed. Thanks.

Support for email addresses

Hi! Let's Encrypt engineer here. I filed an issue over at http-rs/tide-acme#2 requesting that tide-acme show how to include an email address in the example code. @joshtriplett pointed out that email addresses are actually not supported by rustls-acme. Could I ask you to add support for providing an email address? Our experience with ACME clients has been that people don't go out of their way to configure an email address if it's not in the default, but if it is in the default, they're usually happy to provide it.

Providing the email address has a lot of advantages. The main one is that the user can get expiration emails, but also when clients are buggy and spam the service, we really make an effort to connect the user with the client developer so the bugs can be fixed. That starts with an email to the user. Also, we occasionally make breaking changes to our API and need to email our users about it.

If the example email domain is, e.g. example.com, Boulder will reject it until the user provides a different email address.

Release 0.4.0

I just published 0.4.0-beta2 on crates.io and would like to release 0.4.0 in a few days. The main changes are:

  • Switched to rustls 0.20
  • Switched to futures-rustls instead of async-rustls
  • Use separate rustls ServerConfig for connections that aren't acme validation attempts.
  • Hand over control over non-validation connections to the user after TLS server hello in low level API.

The high level API did not change, besides using types from futures-rustls instead of async-rustls. This makes the low level API less opinionated and allows the user to do anything they want with incoming connections.
This enables many new usecases via the low level API:
-Using alpn with non-validation connections
-Mixing other certificate sources by wrapping custom resolvers around the the rutsls-acme resolver
-Client authentication

Feedback and test results are much appreciated.
@joshtriplett : You may want to test how ergonomic the changed API is on your side. You may want to have a look at the axum features as well. Maybe there's something similar you would like to upstream.

solve tide-acme update block

tide-acme can't update to the current version of rustls-acme, because it requires async-rustls streams, instead of the futures-rustls streams we use nowadays.

Upstreaming the meat of tide-acme could be desirable as well, to prevent similar problems going forward.

From #28:

Yes, that's unfortunate. I'm a little fuzzy on the details atm, because I switched such a long time ago. I see three ways forward:

  1. Figure out if we can convert the types. I suspect that's not that hard. I think async-rustls is just missing a From impl we can use.
  2. I could switch back. This is only an option if async-rustls has caught up in term of features (not entirely sure anymore what exactly was missing). futures-rustls is a lot more popular though.
  3. Given how much more popular futures-rustls has become and how redundant async-rustls and futures-rustls are (is that correct?), maybe it is time to explore consolidating by switching over on the tide-rustls side.

No way to configure ALPN settings

Hi, while trying to use rustls-acme with tonic, we ran into problems that I think are related to not having the ability to configure rustls ALPN settings. (Full context is here: penumbra-zone/penumbra#1666 (comment))

Currently, the rustls-acme API doesn't allow setting rustls ServerConfig at all.

Would it be preferable to expose the entire ServerConfig as part of the AcmeConfig builder API, or just the ALPN settings?

Document relationship to rustls config better

The relationship/interactions of this crate to rustls configs isn't very obviously documented. The high level methods on AcmeConfig also don't allow supplying your own rustls config. This may be good as is... or not.
Maybe the high-level incoming() should be extended by adding a variant which gives the user more control over the rustls details via a callback (just providing may not be enough for all usecases as the reliance of this crate on checking alpn before picking a config demonstrates).

Add domains on the fly

Hi,
I am implemententing an auto-whitelabel fature on my service based on the host. For this i use wildcard dns resolution, and allow clients to register custom domains on the same service that will change based on host, at least one subdomain is provided.
Is this crate capable of adding new domains on the fly ?

Bump axum server "0.5.0

Hello,

Could you update axum server to 0.5 ?
I tested, I compiles.
If you prefer, I can make a PR.

Best regards.

Example for tokio/axum

Hello,

I have been trying to adapt the tokio/axum tls example here : https://github.com/tokio-rs/axum/blob/main/examples/low-level-rustls/src/main.rs to use with rustls-acme, but I am stuck because the acceptor does not accept a stream, and since tokio does not have the incoming method on the tcp listener, i cannot extract the tcp object as in

while let Some(tcp) = listener.incoming().next().await {
.

Could you provide an example to be used with tokio based frameworks, ideally with axum ? (but it could be useful with actix too).

Thanks.
Best regards.

Error handling incoming event variant 'processing'

Running into issues getting a certificate to validate because I keep receiving processing events which presumably should map to pending.

Sample

Running `target/debug/examples/high_level_tokio -d [some.real.domain]`
2023-03-28T11:32:00.196Z INFO [rustls_acme::caches::no] no cert cache configured, could not load certificate
2023-03-28T11:32:00.196Z INFO [rustls_acme::caches::no] no account cache configured, could not load account
2023-03-28T11:32:00.196Z INFO [rustls_acme::caches::no] no account cache configured, could not store account
2023-03-28T11:32:00.196Z INFO [rustls_acme::incoming] event: AccountCacheStore
2023-03-28T11:32:01.449Z INFO [rustls_acme::state] trigger challenge for [some.real.domain]
2023-03-28T11:32:02.050Z INFO [rustls_acme::incoming] received TLS-ALPN-01 validation request
2023-03-28T11:32:02.332Z INFO [rustls_acme::incoming] received TLS-ALPN-01 validation request
2023-03-28T11:32:03.206Z INFO [rustls_acme::state] authorization for [some.real.domain] still pending
2023-03-28T11:32:03.595Z INFO [rustls_acme::incoming] received TLS-ALPN-01 validation request
2023-03-28T11:32:03.772Z INFO [rustls_acme::incoming] received TLS-ALPN-01 validation request
2023-03-28T11:32:03.777Z INFO [rustls_acme::incoming] received TLS-ALPN-01 validation request
2023-03-28T11:32:05.129Z INFO [rustls_acme::incoming] received TLS-ALPN-01 validation request
2023-03-28T11:32:05.906Z INFO [rustls_acme::state] completed all authorizations
2023-03-28T11:32:05.906Z INFO [rustls_acme::state] sending csr
2023-03-28T11:32:06.264Z ERROR [rustls_acme::incoming] event: Order(Acme(Json(Error("unknown variant `processing`, expected one of `pending`, `ready`, `valid`, `invalid`", line: 2, column: 24))))
2023-03-28T11:32:08.154Z INFO [rustls_acme::state] sending csr
2023-03-28T11:32:08.511Z ERROR [rustls_acme::incoming] event: Order(Acme(Json(Error("unknown variant `processing`, expected one of `pending`, `ready`, `valid`, `invalid`", line: 2, column: 24))))
2023-03-28T11:32:11.405Z INFO [rustls_acme::state] sending csr
2023-03-28T11:32:11.766Z ERROR [rustls_acme::incoming] event: Order(Acme(Json(Error("unknown variant `processing`, expected one of `pending`, `ready`, `valid`, `invalid`", line: 2, column: 24))))

Presumably

rustls-acme/src/acme.rs

Lines 216 to 228 in 984055c

pub enum Order {
Pending {
authorizations: Vec<String>,
finalize: String,
},
Ready {
finalize: String,
},
Valid {
certificate: String,
},
Invalid,
}
needs to be extended.

Substituted domain name for [some.real.domain] in the logs

runtime independent refresh loop spawning

I'm using custom wakers in async-ws to achieve runtime independence. Maybe the refresh loop should use tasks awaiting the stream to run using the same mechanism.

Update to rustls 0.21

The latest release is 0.21, so this currently can't be used with it unfortunately

Report subdependency build errors

cargo build -Z minimal-versions runs into issues because subdependencies are versioned incorrectly or specify wrong minimal versions. This should probably be resolved upstream.

Consider returning events from `Incoming`

Some events may be of interest to users of the simpler Incoming api. The exact item type is a bit tricky, because we already have a fully populated Result<TlsStream<Tcp>,TcpError>, which isn't easily extended with the event type, which covers both positive and error events.
Relevant comment: #18 (comment)

adding a log_events() method, which filters out Events and does the appropriate logging may be a good idea, to get the current behavior without much extra code.

Issue running multiple instances of bind_listen_serve in same process

Thanks for this crate!

We're writing a web service that uses rustls-acme to get TLS certificates from Let's Encrypt. We have integration tests that run in the same process, and are running into issues when running two instances of rustls-acme::bind_listen_serve simultaneously.

We ran into this originally when running one instance of rustls-acme::bind_listen_serve with no cache directory configured, and then running an instance with a cache directory configured. When doing this, it seemed like the second instance didn't run with a cache directory.

I wanted to open this issue to ask, is there any shared state which might cause problems when running multiple instances of rustls-acme::bind_listen_serve in the same process? I poked around looking for things like lazy_static, or const mutexes, but couldn't find anything.

More context in example

Hey @FlorianUekermann ,

I have trouble understanding both low and high API, would you mind having some context / documentation about what is the acme server address we have to reach, the port, how to stop the server once it's done (is a detach the only action required ? How does it work with tokio then ?) and all the other things you might seem necessary

Best,
Ange

Error after serving HTTP request over TLS

Thanks for rustls-acme! We're using it to automatically fetch TLS certs for a daemon, and it's working great.

We're using the low-level interface, because we're using tokio, so we're configuring ResolvesServerCertUsingAcme but otherwise doing everything ourselves.

You can see our code here.

Fetching certs and serving connections is working perfectly, but the result of Http::new().serve_connection(tls_stream, request_handler).await is returning an error.

You can see the log::error! that's firing here.

The specific error message is:

[2021-10-20T22:22:10Z ERROR agora::https_request_handler] Error closing TLS connection: connection error: not connected

This isn't causing any problems for us, although we'd like to be able to stop ignoring this error, in case it masks more serious errors in the future, so we wanted to ask if you've seen this error before, or if you had any ideas as to what might be the problem.

Our TLS knowledge is pretty fuzzy, and it seems likely that this actually isn't a rustls-acme issue, but maybe an issue with our code, or with a lower-level crate, like rustls or hyper, but we thought we'd start with an issue here.

Callback when certs change

I have a subprocess that needs to be restarted when the certs change. I didn't see a way for the user to get notified when they change - would it be difficult to add that as a feature?

Tonic support

I see there is Warp and Axum support.

It would be awesome to get Tonic support too

support building without ring or aws-lc-rs

Since aws-lc-rs support was added, most of the library is built around rustls::crypto::CryptoProvider to be generic over aws-lc-rs and ring. It would be nice to use something similar for the remaining bits, which covers more of the ring functionality than rustls::crypto::CryptoProvider. Maybe something like this already exists in the ecosystem... ...or maybe we should implement our own provider.
The crypto provider choice also trickles down to rcgen, which may be a problem.

@joshtriplett : Do you have any input on this?

Url trait error while building

I get this error when trying to build a project with rustls-acme

error[E0277]: the trait bound `Url: From<&str>` is not satisfied
  --> C:\Users\Lucas\.cargo\registry\src\github.com-1ecc6299db9ec823\rustls-acme-0.1.6\src\https_helper.rs:16:23
   |
16 |     let mut request = Request::new(method, url.as_ref());
   |                       ^^^^^^^^^^^^ the trait `From<&str>` is not implemented for `Url`
   |
   = note: required because of the requirements on the impl of `std::convert::Into<Url>` for `&str`
   = note: required because of the requirements on the impl of `TryFrom<&str>` for `Url`

Maybe one of the dependencies is broken?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.