mirror of
https://git.anonymousland.org/anonymousland/synapse-product.git
synced 2024-10-01 08:25:44 -04:00
Add an export_signing_key script (#6546)
I want to do some key rotation, and it is silly that we don't have a way to do this.
This commit is contained in:
parent
d6752ce5da
commit
b95b762560
1
changelog.d/6546.feature
Normal file
1
changelog.d/6546.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Add an export_signing_key script to extract the public part of signing keys when rotating them.
|
@ -137,6 +137,7 @@ Some guidelines follow:
|
|||||||
correctly handles the top-level option being set to `None` (as it
|
correctly handles the top-level option being set to `None` (as it
|
||||||
will be if no sub-options are enabled).
|
will be if no sub-options are enabled).
|
||||||
- Lines should be wrapped at 80 characters.
|
- Lines should be wrapped at 80 characters.
|
||||||
|
- Use two-space indents.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -155,13 +156,13 @@ Example:
|
|||||||
# Settings for the frobber
|
# Settings for the frobber
|
||||||
#
|
#
|
||||||
frobber:
|
frobber:
|
||||||
# frobbing speed. Defaults to 1.
|
# frobbing speed. Defaults to 1.
|
||||||
#
|
#
|
||||||
#speed: 10
|
#speed: 10
|
||||||
|
|
||||||
# frobbing distance. Defaults to 1000.
|
# frobbing distance. Defaults to 1000.
|
||||||
#
|
#
|
||||||
#distance: 100
|
#distance: 100
|
||||||
|
|
||||||
Note that the sample configuration is generated from the synapse code
|
Note that the sample configuration is generated from the synapse code
|
||||||
and is maintained by a script, `scripts-dev/generate_sample_config`.
|
and is maintained by a script, `scripts-dev/generate_sample_config`.
|
||||||
|
@ -1122,14 +1122,19 @@ metrics_flags:
|
|||||||
signing_key_path: "CONFDIR/SERVERNAME.signing.key"
|
signing_key_path: "CONFDIR/SERVERNAME.signing.key"
|
||||||
|
|
||||||
# The keys that the server used to sign messages with but won't use
|
# The keys that the server used to sign messages with but won't use
|
||||||
# to sign new messages. E.g. it has lost its private key
|
# to sign new messages.
|
||||||
#
|
#
|
||||||
#old_signing_keys:
|
old_signing_keys:
|
||||||
# "ed25519:auto":
|
# For each key, `key` should be the base64-encoded public key, and
|
||||||
# # Base64 encoded public key
|
# `expired_ts`should be the time (in milliseconds since the unix epoch) that
|
||||||
# key: "The public part of your old signing key."
|
# it was last used.
|
||||||
# # Millisecond POSIX timestamp when the key expired.
|
#
|
||||||
# expired_ts: 123456789123
|
# It is possible to build an entry from an old signing.key file using the
|
||||||
|
# `export_signing_key` script which is provided with synapse.
|
||||||
|
#
|
||||||
|
# For example:
|
||||||
|
#
|
||||||
|
#"ed25519:id": { key: "base64string", expired_ts: 123456789123 }
|
||||||
|
|
||||||
# How long key response published by this server is valid for.
|
# How long key response published by this server is valid for.
|
||||||
# Used to set the valid_until_ts in /key/v2 APIs.
|
# Used to set the valid_until_ts in /key/v2 APIs.
|
||||||
|
94
scripts/export_signing_key
Executable file
94
scripts/export_signing_key
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import nacl.signing
|
||||||
|
from signedjson.key import encode_verify_key_base64, get_verify_key, read_signing_keys
|
||||||
|
|
||||||
|
|
||||||
|
def exit(status: int = 0, message: Optional[str] = None):
|
||||||
|
if message:
|
||||||
|
print(message, file=sys.stderr)
|
||||||
|
sys.exit(status)
|
||||||
|
|
||||||
|
|
||||||
|
def format_plain(public_key: nacl.signing.VerifyKey):
|
||||||
|
print(
|
||||||
|
"%s:%s %s"
|
||||||
|
% (public_key.alg, public_key.version, encode_verify_key_base64(public_key),)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def format_for_config(public_key: nacl.signing.VerifyKey, expiry_ts: int):
|
||||||
|
print(
|
||||||
|
' "%s:%s": { key: "%s", expired_ts: %i }'
|
||||||
|
% (
|
||||||
|
public_key.alg,
|
||||||
|
public_key.version,
|
||||||
|
encode_verify_key_base64(public_key),
|
||||||
|
expiry_ts,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"key_file", nargs="+", type=argparse.FileType("r"), help="The key file to read",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-x",
|
||||||
|
action="store_true",
|
||||||
|
dest="for_config",
|
||||||
|
help="format the output for inclusion in the old_signing_keys config setting",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--expiry-ts",
|
||||||
|
type=int,
|
||||||
|
default=int(time.time() * 1000) + 6*3600000,
|
||||||
|
help=(
|
||||||
|
"The expiry time to use for -x, in milliseconds since 1970. The default "
|
||||||
|
"is (now+6h)."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
formatter = (
|
||||||
|
(lambda k: format_for_config(k, args.expiry_ts))
|
||||||
|
if args.for_config
|
||||||
|
else format_plain
|
||||||
|
)
|
||||||
|
|
||||||
|
keys = []
|
||||||
|
for file in args.key_file:
|
||||||
|
try:
|
||||||
|
res = read_signing_keys(file)
|
||||||
|
except Exception as e:
|
||||||
|
exit(
|
||||||
|
status=1,
|
||||||
|
message="Error reading key from file %s: %s %s"
|
||||||
|
% (file.name, type(e), e),
|
||||||
|
)
|
||||||
|
res = []
|
||||||
|
for key in res:
|
||||||
|
formatter(get_verify_key(key))
|
@ -108,7 +108,7 @@ class KeyConfig(Config):
|
|||||||
self.signing_key = self.read_signing_keys(signing_key_path, "signing_key")
|
self.signing_key = self.read_signing_keys(signing_key_path, "signing_key")
|
||||||
|
|
||||||
self.old_signing_keys = self.read_old_signing_keys(
|
self.old_signing_keys = self.read_old_signing_keys(
|
||||||
config.get("old_signing_keys", {})
|
config.get("old_signing_keys")
|
||||||
)
|
)
|
||||||
self.key_refresh_interval = self.parse_duration(
|
self.key_refresh_interval = self.parse_duration(
|
||||||
config.get("key_refresh_interval", "1d")
|
config.get("key_refresh_interval", "1d")
|
||||||
@ -199,14 +199,19 @@ class KeyConfig(Config):
|
|||||||
signing_key_path: "%(base_key_name)s.signing.key"
|
signing_key_path: "%(base_key_name)s.signing.key"
|
||||||
|
|
||||||
# The keys that the server used to sign messages with but won't use
|
# The keys that the server used to sign messages with but won't use
|
||||||
# to sign new messages. E.g. it has lost its private key
|
# to sign new messages.
|
||||||
#
|
#
|
||||||
#old_signing_keys:
|
old_signing_keys:
|
||||||
# "ed25519:auto":
|
# For each key, `key` should be the base64-encoded public key, and
|
||||||
# # Base64 encoded public key
|
# `expired_ts`should be the time (in milliseconds since the unix epoch) that
|
||||||
# key: "The public part of your old signing key."
|
# it was last used.
|
||||||
# # Millisecond POSIX timestamp when the key expired.
|
#
|
||||||
# expired_ts: 123456789123
|
# It is possible to build an entry from an old signing.key file using the
|
||||||
|
# `export_signing_key` script which is provided with synapse.
|
||||||
|
#
|
||||||
|
# For example:
|
||||||
|
#
|
||||||
|
#"ed25519:id": { key: "base64string", expired_ts: 123456789123 }
|
||||||
|
|
||||||
# How long key response published by this server is valid for.
|
# How long key response published by this server is valid for.
|
||||||
# Used to set the valid_until_ts in /key/v2 APIs.
|
# Used to set the valid_until_ts in /key/v2 APIs.
|
||||||
@ -290,6 +295,8 @@ class KeyConfig(Config):
|
|||||||
raise ConfigError("Error reading %s: %s" % (name, str(e)))
|
raise ConfigError("Error reading %s: %s" % (name, str(e)))
|
||||||
|
|
||||||
def read_old_signing_keys(self, old_signing_keys):
|
def read_old_signing_keys(self, old_signing_keys):
|
||||||
|
if old_signing_keys is None:
|
||||||
|
return {}
|
||||||
keys = {}
|
keys = {}
|
||||||
for key_id, key_data in old_signing_keys.items():
|
for key_id, key_data in old_signing_keys.items():
|
||||||
if is_signing_algorithm_supported(key_id):
|
if is_signing_algorithm_supported(key_id):
|
||||||
|
Loading…
Reference in New Issue
Block a user