florianuekermann / rustls-acme Goto Github PK
View Code? Open in Web Editor NEWLicense: Apache License 2.0
License: Apache License 2.0
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 modulerustls
|
help: consider importing one of these items
|
1 + use crate::futures_rustls::rustls;
|
1 + use futures_rustls::rustls;
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.
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.
In https_helper.rs, you have hardcoded the root certificates that the https client will accept.
I'm running my own internal CA (https://smallstep.com/), which also offers the ACME protocol. But to be able to use it,
I need rustls-acme to allow modification of the trusted root certificates, i.e. by loading the certs installed on the system.
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.
Replace async-h1.
Hello !
I would like to use this crate with actix-web
. Is this possible ?
I don't see any may to pass rustls-acme's output to actix HTTPServer
Maybe this crate would need to implement ServerServiceFactory
in order to use ServerBuilder::listen
?
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?
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
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.
async-web-client
also to newer versionreqwest
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.
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.
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:
ServerConfig
for connections that aren't acme validation attempts.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.
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:
- 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.- 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.
- 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.
Hello,
I use rustls-acme to create automatically Let's Encrypt certificates like in https://github.com/FlorianUekermann/rustls-acme/blob/main/examples/low_level_axum.rs . It works very well, but the server seems not to respond with HTTP/2, even if the http2 feature is enabled in axum.
How can I enable HTTP/2 ? I think it is something to do with the acceptor and ALPN protocol, but I am kind of stuck...
Thanks and best regards.
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?
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).
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 ?
Hello,
Could you update axum server to 0.5 ?
I tested, I compiles.
If you prefer, I can make a PR.
Best regards.
Please consider providing a Debug
implementation for AcmeAcceptor
, to make it possible to #[derive(Debug)]
for a struct containing AcmeAcceptor
.
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
rustls-acme/examples/server_low_level.rs
Line 62 in 8673b2c
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.
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
Lines 216 to 228 in 984055c
Substituted domain name for [some.real.domain]
in the logs
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.
Pull request #7 highlights that this may be useful for people who want some convenience around the lower level acme API without using the batteries included solution.
The latest release is 0.21
, so this currently can't be used with it unfortunately
cargo build -Z minimal-versions
runs into issues because subdependencies are versioned incorrectly or specify wrong minimal versions. This should probably be resolved upstream.
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 Event
s and does the appropriate logging may be a good idea, to get the current behavior without much extra code.
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.
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
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.
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?
I see there is Warp and Axum support.
It would be awesome to get Tonic support too
crates.io has a version 0.1.8 and 0.2.0, but this repository only has 0.1.7.
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?
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.