Skip to content

Commit 8bd807f

Browse files
authored
Merge pull request #518 from AmbireTech/sentry-tls
Sentry the ability to setup TLS
2 parents 0c9deab + def8a14 commit 8bd807f

File tree

17 files changed

+409
-44
lines changed

17 files changed

+409
-44
lines changed

Cargo.lock

Lines changed: 107 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Dockerfile-sentry

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ ENV KEYSTORE_PWD=
6565
# Only applicable if you use the `--adapter dummy`
6666
ENV DUMMY_IDENTITY=
6767

68+
# To setup TLS supply both `PRIVATE_KEYS` & `CERTIFICATES`
69+
# Otherwise you will get an error
70+
ENV PRIVATE_KEYS=
71+
ENV CERTIFICATES=
72+
6873
# If set it will override the configuration file used
6974
ENV CONFIG=
7075

@@ -85,4 +90,6 @@ ENTRYPOINT ["./scripts/entrypoint.sh"]
8590
CMD sentry -a ${ADAPTER:-ethereum} \
8691
${KEYSTORE_FILE:+-k $KEYSTORE_FILE} \
8792
${DUMMY_IDENTITY:+-i $DUMMY_IDENTITY} \
93+
${PRIVATE_KEYS:+--privateKeys $PRIVATE_KEYS} \
94+
${CERTIFICATES:+--certificates $CERTIFICATES} \
8895
${CONFIG}

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,13 @@ cargo run -p sentry -- --help
5757

5858
Starting the Sentry API in will always run migrations, this will make sure the database is always up to date with the latest migrations, before starting and exposing the web server.
5959

60-
By default, we use the `development` environment ( [`ENV` environment variable](#environment-variables) ) as it will also seed the database.
60+
By default, we use the `development` environment ( [`ENV` environment variable](#environment-variables) ) ~~as it will also seed the database~~ (seeding is disabled, see #514).
61+
62+
To enable TLS for the sentry server you need to pass both `--privateKeys` and
63+
`--certificates` cli options (paths to `.pem` files) otherwise the cli will
64+
exit with an error.
65+
66+
For full list of available addresses see [primitives/src/test_util.rs#L39-L118](./primitives/src/test_util.rs#L39-L118)
6167

6268
#### Using the `Ethereum` adapter
6369

@@ -100,7 +106,7 @@ POSTGRES_DB="sentry_follower" PORT=8006 KEYSTORE_PWD=ganache1 cargo run -p sentr
100106
IP_ADDR=127.0.0.1 REDIS_URL="redis://127.0.0.1:6379/1" \
101107
POSTGRES_DB="sentry_leader" PORT=8005 cargo run -p sentry -- \
102108
--adapter dummy \
103-
--dummyIdentity 80690751969B234697e9059e04ed72195c3507fa \
109+
--dummyIdentity 0x80690751969B234697e9059e04ed72195c3507fa \
104110
./docs/config/prod.toml
105111
```
106112
##### Follower (`0xf3f583AEC5f7C030722Fe992A5688557e1B86ef7`)
@@ -109,19 +115,18 @@ POSTGRES_DB="sentry_leader" PORT=8005 cargo run -p sentry -- \
109115
IP_ADDR=127.0.0.1 REDIS_URL="redis://127.0.0.1:6379/2" \
110116
POSTGRES_DB="sentry_follower" PORT=8006 cargo run -p sentry -- \
111117
--adapter dummy \
112-
--dummyIdentity f3f583AEC5f7C030722Fe992A5688557e1B86ef7 \
118+
--dummyIdentity 0xf3f583AEC5f7C030722Fe992A5688557e1B86ef7 \
113119
./docs/config/prod.toml
114120
```
115121

116-
For full list, check out [primitives/src/util/tests/prep_db.rs#L29-L43](./primitives/src/util/tests/prep_db.rs#L29-L43)
117-
118122
#### Environment variables
119123

120124
- `ENV` - `production` or `development`; *default*: `development` - passing this env. variable will use the default configuration paths - [`docs/config/dev.toml`](./docs/config/dev.toml) (for `development`) or [`docs/config/prod.toml`](./docs/config/prod.toml) (for `production`). Otherwise you can pass your own configuration file path to the binary (check `cargo run -p sentry --help` for more information). In `development` it will make sure Sentry to seed the database.
121125
- `PORT` - *default*: `8005` - The local port that Sentry API will be accessible at
122126
- `IP_ADDR` - *default*: `0.0.0.0` - the IP address that the API should be listening to
123127

124128
##### Adapter
129+
125130
- `KEYSTORE_PWD` - Password for the `Keystore file`, only available when using `Ethereum` adapter (`--adapter ethereum`)
126131

127132
##### Redis

primitives/src/test_util.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ pub static DUMMY_AUTH: Lazy<HashMap<Address, String>> = Lazy::new(|| {
129129
auth.insert(*ADVERTISER, "AUTH_awesomeAdvertiser".into());
130130
auth.insert(*PUBLISHER, "AUTH_awesomePublisher".into());
131131
auth.insert(*GUARDIAN_2, "AUTH_awesomeGuardian2".into());
132+
auth.insert(*PUBLISHER_2, "AUTH_awesomePublisher2".into());
133+
auth.insert(*ADVERTISER_2, "AUTH_awesomeAdvertiser2".into());
134+
auth.insert(*LEADER_2, "AUTH_awesomeLeader2".into());
132135

133136
auth
134137
});

sentry/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ hyper = { version = "0.14", features = [
3232
"stream",
3333
"runtime",
3434
"http1",
35+
"http2",
3536
"server",
3637
] }
38+
simple-hyper-server-tls = { version = "0.3", features = ["tls-rustls"] }
3739
regex = "1"
3840
# Database
3941
redis = { version = "0.21", features = ["aio", "tokio-comp"] }

sentry/src/application.rs

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
1+
use std::{
2+
net::{IpAddr, Ipv4Addr, SocketAddr},
3+
path::Path,
4+
};
25

36
use adapter::client::Locked;
47
use hyper::{
@@ -9,6 +12,7 @@ use once_cell::sync::Lazy;
912
use primitives::{config::Environment, ValidatorId};
1013
use redis::ConnectionInfo;
1114
use serde::{Deserialize, Deserializer};
15+
use simple_hyper_server_tls::{listener_from_pem_files, Protocols, TlsListener};
1216
use slog::{error, info};
1317

1418
use crate::{
@@ -45,6 +49,7 @@ pub static DEFAULT_REDIS_URL: Lazy<ConnectionInfo> = Lazy::new(|| {
4549
#[derive(Debug, Deserialize, Clone)]
4650
pub struct EnvConfig {
4751
/// Defaults to `Development`: [`Environment::default()`]
52+
#[serde(default)]
4853
pub env: Environment,
4954
/// The port on which the Sentry REST API will be accessible.
5055
///
@@ -157,24 +162,52 @@ where
157162

158163
impl<C: Locked + 'static> Application<C> {
159164
/// Starts the `hyper` `Server`.
160-
pub async fn run(self, socket_addr: SocketAddr) {
165+
pub async fn run(self, enable_tls: EnableTls) {
161166
let logger = self.logger.clone();
167+
let socket_addr = match &enable_tls {
168+
EnableTls::NoTls(socket_addr) => socket_addr,
169+
EnableTls::Tls { socket_addr, .. } => socket_addr,
170+
};
171+
162172
info!(&logger, "Listening on socket address: {}!", socket_addr);
163173

164-
let make_service = make_service_fn(|_| {
165-
let server = self.clone();
166-
async move {
167-
Ok::<_, Error>(service_fn(move |req| {
168-
let server = server.clone();
169-
async move { Ok::<_, Error>(server.handle_routing(req).await) }
170-
}))
174+
match enable_tls {
175+
EnableTls::NoTls(socket_addr) => {
176+
let make_service = make_service_fn(|_| {
177+
let server = self.clone();
178+
async move {
179+
Ok::<_, Error>(service_fn(move |req| {
180+
let server = server.clone();
181+
async move { Ok::<_, Error>(server.handle_routing(req).await) }
182+
}))
183+
}
184+
});
185+
186+
let server = Server::bind(&socket_addr).serve(make_service);
187+
188+
if let Err(e) = server.await {
189+
error!(&logger, "server error: {}", e; "main" => "run");
190+
}
171191
}
172-
});
192+
EnableTls::Tls { listener, .. } => {
193+
let make_service = make_service_fn(|_| {
194+
let server = self.clone();
195+
async move {
196+
Ok::<_, Error>(service_fn(move |req| {
197+
let server = server.clone();
198+
async move { Ok::<_, Error>(server.handle_routing(req).await) }
199+
}))
200+
}
201+
});
173202

174-
let server = Server::bind(&socket_addr).serve(make_service);
203+
// TODO: Find a way to redirect to HTTPS
204+
let mut server = Server::builder(listener).serve(make_service);
175205

176-
if let Err(e) = server.await {
177-
error!(&logger, "server error: {}", e; "main" => "run");
206+
while let Err(e) = (&mut server).await {
207+
// This is usually caused by trying to connect on HTTP instead of HTTPS
208+
error!(&logger, "server error: {}", e; "main" => "run");
209+
}
210+
}
178211
}
179212
}
180213
}
@@ -193,6 +226,35 @@ impl<C: Locked> Clone for Application<C> {
193226
}
194227
}
195228

229+
/// Either enable or do not the Tls support.
230+
pub enum EnableTls {
231+
NoTls(SocketAddr),
232+
Tls {
233+
socket_addr: SocketAddr,
234+
listener: TlsListener,
235+
},
236+
}
237+
238+
impl EnableTls {
239+
pub fn new_tls<C: AsRef<Path>, K: AsRef<Path>>(
240+
certificates: C,
241+
private_keys: K,
242+
socket_addr: SocketAddr,
243+
) -> Result<Self, Box<dyn std::error::Error>> {
244+
let listener =
245+
listener_from_pem_files(certificates, private_keys, Protocols::ALL, &socket_addr)?;
246+
247+
Ok(Self::Tls {
248+
listener,
249+
socket_addr,
250+
})
251+
}
252+
253+
pub fn no_tls(socket_addr: SocketAddr) -> Self {
254+
Self::NoTls(socket_addr)
255+
}
256+
}
257+
196258
/// Sentry [`Application`] Session
197259
#[derive(Debug, Clone)]
198260
pub struct Session {

0 commit comments

Comments
 (0)