diff --git a/book/src/admin-guide/deployment/nixos.md b/book/src/admin-guide/deployment/nixos.md
index 45ede64..e5aef81 100644
--- a/book/src/admin-guide/deployment/nixos.md
+++ b/book/src/admin-guide/deployment/nixos.md
@@ -14,13 +14,13 @@ Attic provides [a NixOS module](https://github.com/zhaofengli/attic/blob/main/ni
The RS256 JWT secret can be generated with the `openssl` utility:
```bash
-openssl genrsa -traditional -out private_key.pem 4096
+nix run nixpkgs#openssl -- genrsa -traditional -out - 4096 | base64 -w0
```
Create a file on the server containing the following contents:
```
-ATTIC_SERVER_TOKEN_RS256_SECRET="output from openssl"
+ATTIC_SERVER_TOKEN_RS256_SECRET="output from above"
```
Ensure the file is only accessible by root.
diff --git a/integration-tests/basic/default.nix b/integration-tests/basic/default.nix
index 2165f72..53982d2 100644
--- a/integration-tests/basic/default.nix
+++ b/integration-tests/basic/default.nix
@@ -5,7 +5,7 @@ let
serverConfigFile = config.nodes.server.services.atticd.configFile;
cmd = {
- atticadm = "atticd-atticadm";
+ atticadm = ". /etc/atticd.env && export ATTIC_SERVER_TOKEN_RS256_SECRET && atticd-atticadm";
atticd = ". /etc/atticd.env && export ATTIC_SERVER_TOKEN_RS256_SECRET && atticd -f ${serverConfigFile}";
};
@@ -125,7 +125,7 @@ in {
# For testing only - Don't actually do this
environment.etc."atticd.env".text = ''
- ATTIC_SERVER_TOKEN_RS256_SECRET="$(openssl genrsa -traditional -out - 512)"
+ ATTIC_SERVER_TOKEN_RS256_SECRET='LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBekhqUzFGKzlRaFFUdlJZYjZ0UGhxS09FME5VYkIraTJMOTByWVBNQVVoYVBUMmlKCmVUNk9vWFlmZWszZlZ1dXIrYks1VWFVRjhUbEx2Y1FHa1Arckd0WDRiQUpGTWJBcTF3Y25FQ3R6ZGVERHJnSlIKMGUvNWJhdXQwSS9YS0ticG9oYjNvWVhtUmR5eG9WVGE3akY1bk11ajBsd25kUTcwYTF1ZGkzMGNpYkdTWHZMagpVeGltL3ByYjUrV3ZPdjN4UnhlbDZHYmptUW1RMVBHeHVLcmx3b1ZKRnlWTjl3QmExajBDelJDcURnTFRwQWw0CjhLVWlDY2V1VUZQcmdZaW9vSVhyVExlWmxVbFVVV3FHSDBJbGFKeVUyQ05iNWJtZWM1TnZ4RDlaakFoYytucmgKRS80VzkxajdQMFVyQnp4am9NUTRlKzBPZDhmQnBvSDAwbm4xUXdJREFRQUJBb0lCQUE2RmxEK21Ed3gyM1pJRAoxSGJBbHBuQ0IwaEhvbFJVK0Q5OC96d3k5ZlplaU00VWVCTUcyTjFweE1HTWIweStqeWU4UkVJaXJNSGRsbDRECllvNEF3bmUwODZCRUp3TG81cG4vOVl2RjhqelFla1ZNLzkrZm9nRGlmUVUvZWdIMm5NZzR4bHlQNUhOWXdicmEKQ25SNVNoQlRQQzdRQWJOa0hRTFU3bUwrUHowZUlXaG9KWVRoUUpkU0g3RDB0K1QwZzVVNDdPam5qbXJaTWwxaApHOE1IUHhKMk5WU1l2N0dobnpjblZvcVVxYzlxeldXRDZXZERtV1BPNGJ1K2p0b2E2U2o4cjJtb0RRZ1A5YXNhCm93RUFJbHBmbVkxYUx2dENwWG4rejRTTWJKcHRXMlVvaktGa2dkYm9jZmtXYWdtSGZRa2xmS0dBQ0hibU9ZV24KeDRCbTU3a0NnWUVBN1dXaXJDZnBRR01hR3A2WWxMQlVUc1VJSXJOclF4UmtuRlc3dFVYd0NqWFZ5SDlTR3FqNgphTkNhYzZpaks3QVNBYXlxY1JQRjFPY2gyNmxpVmRKUHNuRGxwUjhEVXB2TzRVOVRzSTJyZ1lZYzNrSWkzVGFKClgzV0Vic1Z6Nk45WXFPSXlnVnZiTEhLS0F4Uyt4b1Z2SjkzQmdWRHN5SkxRdmhrM3VubXk3M2tDZ1lFQTNINnYKeUhOKzllOVAyOS9zMVY1eWZxSjdvdVdKV0lBTHFDYm9zOTRRSVdPSG5HRUtSSGkydWIzR0d6U2tRSzN1eTUrdQo4M0txaFJOejRVMkdOK1pLaFE0NHhNVmV4TUVvZzJVU3lTaVZ0cFdqWXBwT2Q1NnVaMzRWaFU2TWRNZS9zT0JnCnNoei84MUxUSis2cHdFZE9wV2tPVlRaMXJISlZXQmdtVk5qWjc1c0NnWUVBNVd5YjBaU2dyMEVYTVRLa2NzNFcKTENudXV0cDZodEZtaWsrd29IZCtpOStMUThFSU1BdXVOUzJrbHJJYlAxVmhrWXkxQzZMNFJkRTV2M2ZyT05XUApmL3ZyYzdDTkhZREdacWlyVUswWldvdXB5b0pQLzBsOWFXdkJHT3hxSUZ2NDZ2M3ZvV1NNWkdBdFVOenpvaGZDClhOeks3WmF2dndka0JOT0tNQVQ5RU1FQ2dZRUF3NEhaWDRWNUo1d2dWVGVDQ2RjSzhsb2tBbFpBcUNZeEw5SUEKTjZ4STVUSVpSb0dNMXhXcC81dlRrci9rZkMwOU5YUExiclZYbVZPY1JrTzFKTStmZDhjYWN1OEdqck11dHdMaAoyMWVQR0N3cWlQMkZZZTlqZVFTRkZJU0hhZXpMZll3V2NSZmhvdURudGRxYXpaRHNuU0kvd1RMZXVCOVFxU0lRCnF0NzByczBDZ1lCQ2lzV0VKdXpQUUlJNzVTVkU4UnJFZGtUeUdhOEVBOHltcStMdDVLRDhPYk80Q2JHYVFlWXkKWFpjSHVyOFg2cW1lWHZVU3MwMHBMMUdnTlJ3WCtSUjNMVDhXTm9vc0NqVDlEUW9GOFZveEtseDROVTRoUGlrTQpBc0w1RS9wYnVLeXkvSU5LTnQyT3ZPZmJYVitlTXZQdGs5c1dORjNyRTBYcU15TW9maG9NaVE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo='
'';
services.atticd = {
diff --git a/nixos/atticd.nix b/nixos/atticd.nix
index a33b415..b8b678a 100644
--- a/nixos/atticd.nix
+++ b/nixos/atticd.nix
@@ -16,7 +16,7 @@ let
} ''
cat $configFile
- export ATTIC_SERVER_TOKEN_RS256_SECRET="$(${pkgs.openssl}/bin/openssl genrsa -traditional -out - 512)"
+ export ATTIC_SERVER_TOKEN_RS256_SECRET="$(${pkgs.openssl}/bin/openssl genrsa -traditional -out - 1024 | ${pkgs.coreutils}/bin/base64 -w0)"
export ATTIC_SERVER_DATABASE_URL="sqlite://:memory:"
${cfg.package}/bin/atticd --mode check-config -f $configFile
cat <$configFile >$out
@@ -79,7 +79,7 @@ in
variables:
- ATTIC_SERVER_TOKEN_RS256_SECRET: The PEM-encoded version of the
- RS256 JWT secret. Generate it with `openssl genrsa -traditional -out private_key.pem 4096`.
+ RS256 JWT secret. Generate it with `openssl genrsa -traditional -out - 4096 | base64 -w0`.
'';
type = types.nullOr types.path;
default = null;
@@ -135,7 +135,7 @@ in
message = ''
is not set.
- Run `openssl genrsa -traditional -out private_key.pem 4096` and create a file with the following contents:
+ Run `openssl genrsa -traditional -out private_key.pem 4096 | base64 -w0` and create a file with the following contents:
ATTIC_SERVER_TOKEN_RS256_SECRET="output from command"
diff --git a/server/src/config-template.toml b/server/src/config-template.toml
index ba67689..58e398f 100644
--- a/server/src/config-template.toml
+++ b/server/src/config-template.toml
@@ -36,7 +36,7 @@ allowed-hosts = []
# JWT signing token
#
-# Set this to the PEM encoding of some random data.
+# Set this to the base64-encoded, then PEM encoding of an RSA key.
# You can also set it via the `ATTIC_SERVER_TOKEN_RS256_SECRET` environment
# variable.
token-rs256-secret = "%token_rs256_secret%"
diff --git a/server/src/config.rs b/server/src/config.rs
index c3b605a..e99fd63 100644
--- a/server/src/config.rs
+++ b/server/src/config.rs
@@ -26,7 +26,7 @@ const XDG_PREFIX: &str = "attic";
/// This is useful for deploying to certain application platforms like Fly.io
const ENV_CONFIG_BASE64: &str = "ATTIC_SERVER_CONFIG_BASE64";
-/// Environment variable storing the PEM-encoded RS256 JWT secret.
+/// Environment variable storing the base64 encoded, then PEM-encoded RS256 JWT secret.
const ENV_TOKEN_RS256_SECRET: &str = "ATTIC_SERVER_TOKEN_RS256_SECRET";
/// Environment variable storing the database connection string.
diff --git a/token/Cargo.toml b/token/Cargo.toml
index d49ac98..f549dd2 100644
--- a/token/Cargo.toml
+++ b/token/Cargo.toml
@@ -11,7 +11,7 @@ attic = { path = "../attic", default-features = false }
base64 = "0.21.2"
chrono = "0.4.24"
displaydoc = "0.2.4"
-jsonwebtoken = "9.1.0"
+jsonwebtoken = { version = "9.1.0", features = ["use_pem"] }
lazy_static = "1.4.0"
regex = "1.8.3"
serde = "1.0.163"
diff --git a/token/src/lib.rs b/token/src/lib.rs
index 3cfd46f..1e0fd41 100644
--- a/token/src/lib.rs
+++ b/token/src/lib.rs
@@ -93,6 +93,7 @@ pub use jsonwebtoken::{DecodingKey, EncodingKey};
use rsa::pkcs1::{DecodeRsaPrivateKey, EncodeRsaPublicKey};
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, BoolFromInt};
+use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine};
use attic::cache::{CacheName, CacheNamePattern};
@@ -272,8 +273,14 @@ pub enum Error {
/// JWT error: {0}
TokenError(jsonwebtoken::errors::Error),
+ /// Base64 decode error: {0}
+ Base64Error(base64::DecodeError),
+
/// RSA Key error: {0}
RsaKeyError(rsa::pkcs1::Error),
+
+ /// Failure decoding the base64 layer of the base64 encoded PEM
+ Utf8Error(std::str::Utf8Error)
}
impl Token {
@@ -285,7 +292,7 @@ impl Token {
validation.validate_nbf = true;
// validation.set_issuer(&[ctx.config.flakehub_jwt_bound_issuer.clone()]);
// validation.set_audience(&[ctx.config.jwt_bound_audience.clone()]);
- validation.set_required_spec_claims(&["exp", "nbf", "aud", "iss", "sub"]);
+ //validation.set_required_spec_claims(&["exp", "nbf", "aud", "iss", "sub"]);
jsonwebtoken::decode::>(token, key, &validation)
.map_err(Error::TokenError)
@@ -314,7 +321,8 @@ impl Token {
/// Encodes the token.
pub fn encode(&self, key: &jsonwebtoken::EncodingKey) -> Result {
- let header = jsonwebtoken::Header::default();
+ let mut header = jsonwebtoken::Header::default();
+ header.alg = Algorithm::RS256;
jsonwebtoken::encode(&header, &self.0, key).map_err(Error::TokenError)
}
@@ -420,14 +428,17 @@ impl CachePermission {
impl StdError for Error {}
-pub fn decode_token_rs256_secret(secret: &str) -> Result<(EncodingKey, DecodingKey)> {
+pub fn decode_token_rs256_secret(s: &str) -> Result<(EncodingKey, DecodingKey)> {
+ let decoded = BASE64_STANDARD.decode(s).map_err(Error::Base64Error)?;
+ let secret = std::str::from_utf8(&decoded).map_err(Error::Utf8Error)?;
+
let private_key = rsa::RsaPrivateKey::from_pkcs1_pem(secret).map_err(Error::RsaKeyError)?;
let public_key = private_key.to_public_key();
let public_pkcs1_pem = public_key
.to_pkcs1_pem(rsa::pkcs1::LineEnding::LF)
.map_err(Error::RsaKeyError)?;
- let encoding_key = EncodingKey::from_rsa_pem(secret.as_bytes()).map_err(Error::TokenError)?;
+ let encoding_key = EncodingKey::from_rsa_pem(&secret.as_bytes()).map_err(Error::TokenError)?;
let decoding_key =
DecodingKey::from_rsa_pem(public_pkcs1_pem.as_bytes()).map_err(Error::TokenError)?;