Merge pull request #28082 from mrc0mmand/more-journal-remote-tests

test: add a couple of tests for systemd-journal-{remote,upload}
This commit is contained in:
Luca Boccassi
2023-06-20 23:38:24 +01:00
committed by GitHub
9 changed files with 371 additions and 134 deletions
+45 -69
View File
@@ -16,6 +16,7 @@
#include "main-func.h"
#include "memory-util.h"
#include "parse-argument.h"
#include "parse-helpers.h"
#include "pretty-print.h"
#include "process-util.h"
#include "rlimit-util.h"
@@ -369,8 +370,8 @@ static int setup_microhttpd_server(RemoteServer *s,
const char *cert,
const char *trust) {
struct MHD_OptionItem opts[] = {
{ MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
{ MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
{ MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
{ MHD_OPTION_LISTEN_SOCKET, fd},
{ MHD_OPTION_CONNECTION_MEMORY_LIMIT, 128*1024},
{ MHD_OPTION_END},
@@ -385,9 +386,9 @@ static int setup_microhttpd_server(RemoteServer *s,
MHD_USE_EPOLL |
MHD_USE_ITC;
_cleanup_(MHDDaemonWrapper_freep) MHDDaemonWrapper *d = NULL;
const union MHD_DaemonInfo *info;
int r, epoll_fd;
MHDDaemonWrapper *d;
assert(fd >= 0);
@@ -435,75 +436,49 @@ static int setup_microhttpd_server(RemoteServer *s,
request_handler, NULL,
MHD_OPTION_ARRAY, opts,
MHD_OPTION_END);
if (!d->daemon) {
log_error("Failed to start μhttp daemon");
r = -EINVAL;
goto error;
}
if (!d->daemon)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to start μhttp daemon");
log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
key ? "HTTPS" : "HTTP", fd, d);
info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
if (!info) {
log_error("μhttp returned NULL daemon info");
r = -EOPNOTSUPP;
goto error;
}
if (!info)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "μhttp returned NULL daemon info");
epoll_fd = info->listen_fd;
if (epoll_fd < 0) {
log_error("μhttp epoll fd is invalid");
r = -EUCLEAN;
goto error;
}
if (epoll_fd < 0)
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), "μhttp epoll fd is invalid");
r = sd_event_add_io(s->events, &d->io_event,
epoll_fd, EPOLLIN,
dispatch_http_event, d);
if (r < 0) {
log_error_errno(r, "Failed to add event callback: %m");
goto error;
}
if (r < 0)
return log_error_errno(r, "Failed to add event callback: %m");
r = sd_event_source_set_description(d->io_event, "io_event");
if (r < 0) {
log_error_errno(r, "Failed to set source name: %m");
goto error;
}
if (r < 0)
return log_error_errno(r, "Failed to set source name: %m");
r = sd_event_add_time(s->events, &d->timer_event,
CLOCK_MONOTONIC, UINT64_MAX, 0,
null_timer_event_handler, d);
if (r < 0) {
log_error_errno(r, "Failed to add timer_event: %m");
goto error;
}
if (r < 0)
return log_error_errno(r, "Failed to add timer_event: %m");
r = sd_event_source_set_description(d->timer_event, "timer_event");
if (r < 0) {
log_error_errno(r, "Failed to set source name: %m");
goto error;
}
if (r < 0)
return log_error_errno(r, "Failed to set source name: %m");
r = hashmap_ensure_put(&s->daemons, &uint64_hash_ops, &d->fd, d);
if (r == -ENOMEM) {
log_oom();
goto error;
}
if (r < 0) {
log_error_errno(r, "Failed to add daemon to hashmap: %m");
goto error;
}
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to add daemon to hashmap: %m");
TAKE_PTR(d);
s->active++;
return 0;
error:
MHD_stop_daemon(d->daemon);
free(d->daemon);
free(d);
return r;
}
static int setup_microhttpd_socket(RemoteServer *s,
@@ -762,7 +737,7 @@ static int parse_config(void) {
{ "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
{ "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
{ "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
{ "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{ "Remote", "TrustedCertificateFile", config_parse_path_or_ignore, 0, &arg_trust },
{ "Remote", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
{ "Remote", "MaxFileSize", config_parse_iec_uint64, 0, &arg_max_size },
{ "Remote", "MaxFiles", config_parse_uint64, 0, &arg_n_max_files },
@@ -866,7 +841,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_URL:
if (arg_url)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot currently set more than one --url");
"Cannot currently set more than one --url=");
arg_url = optarg;
break;
@@ -874,7 +849,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_GETTER:
if (arg_getter)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot currently use --getter more than once");
"Cannot currently use --getter= more than once");
arg_getter = optarg;
break;
@@ -882,7 +857,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_LISTEN_RAW:
if (arg_listen_raw)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot currently use --listen-raw more than once");
"Cannot currently use --listen-raw= more than once");
arg_listen_raw = optarg;
break;
@@ -890,7 +865,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_LISTEN_HTTP:
if (arg_listen_http || http_socket >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot currently use --listen-http more than once");
"Cannot currently use --listen-http= more than once");
r = negative_fd(optarg);
if (r >= 0)
@@ -902,7 +877,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_LISTEN_HTTPS:
if (arg_listen_https || https_socket >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot currently use --listen-https more than once");
"Cannot currently use --listen-https= more than once");
r = negative_fd(optarg);
if (r >= 0)
@@ -936,27 +911,23 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_TRUST:
#if HAVE_GNUTLS
if (arg_trust || arg_trust_all)
if (arg_trust)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Confusing trusted CA configuration");
"Cannot use --trust more= than once");
if (streq(optarg, "all"))
arg_trust_all = true;
else {
arg_trust = strdup(optarg);
if (!arg_trust)
return log_oom();
}
arg_trust = strdup(optarg);
if (!arg_trust)
return log_oom();
#else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --trust is not available.");
"Option --trust= is not available.");
#endif
break;
case 'o':
if (arg_output)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use --output/-o more than once");
"Cannot use --output=/-o more than once");
r = parse_path_argument(optarg, /* suppress_root = */ false, &arg_output);
if (r < 0)
@@ -1000,7 +971,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
#else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --gnutls-log is not available.");
"Option --gnutls-log= is not available.");
#endif
case '?':
@@ -1020,12 +991,12 @@ static int parse_argv(int argc, char *argv[]) {
|| sd_listen_fds(false) > 0;
if (type_a && type_b)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot use file input or --getter with "
"--arg-listen-... or socket activation.");
"Cannot use file input or --getter= with "
"--listen-...= or socket activation.");
if (type_a) {
if (!arg_output)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --output must be specified with file input or --getter.");
"Option --output= must be specified with file input or --getter=.");
if (!IN_SET(arg_split_mode, JOURNAL_WRITE_SPLIT_NONE, _JOURNAL_WRITE_SPLIT_INVALID))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@@ -1051,6 +1022,11 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"For SplitMode=host, output must be a directory.");
if (STRPTR_IN_SET(arg_trust, "-", "all")) {
arg_trust_all = true;
arg_trust = mfree(arg_trust);
}
log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
journal_write_split_mode_to_string(arg_split_mode),
strna(arg_key),
@@ -1096,7 +1072,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
if ((arg_listen_raw || arg_listen_http) && *trust)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --trust makes all non-HTTPS connections untrusted.");
"Option --trust= makes all non-HTTPS connections untrusted.");
return 0;
}
+38 -15
View File
@@ -20,6 +20,7 @@
#include "macro.h"
#include "managed-journal-file.h"
#include "parse-util.h"
#include "parse-helpers.h"
#include "process-util.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -30,11 +31,28 @@
#define filename_escape(s) xescape((s), "/ ")
#if HAVE_MICROHTTPD
MHDDaemonWrapper *MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
if (!d)
return NULL;
if (d->daemon)
MHD_stop_daemon(d->daemon);
sd_event_source_unref(d->io_event);
sd_event_source_unref(d->timer_event);
return mfree(d);
}
#endif
static int open_output(RemoteServer *s, Writer *w, const char* host) {
_cleanup_free_ char *_filename = NULL;
const char *filename;
int r;
assert(s);
assert(w);
switch (s->split_mode) {
case JOURNAL_WRITE_SPLIT_NONE:
filename = s->output;
@@ -104,6 +122,9 @@ int journal_remote_get_writer(RemoteServer *s, const char *host, Writer **writer
const void *key;
int r;
assert(s);
assert(writer);
switch (s->split_mode) {
case JOURNAL_WRITE_SPLIT_NONE:
key = "one and only";
@@ -172,6 +193,7 @@ static int get_source_for_fd(RemoteServer *s,
/* This takes ownership of name, but only on success. */
assert(s);
assert(fd >= 0);
assert(source);
@@ -275,10 +297,11 @@ int journal_remote_add_source(RemoteServer *s, int fd, char* name, bool own_name
}
int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
int r;
_unused_ _cleanup_close_ int fd_ = fd;
char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
int r;
assert(s);
assert(fd >= 0);
r = sd_event_add_io(s->events, &s->listen_event,
@@ -293,7 +316,7 @@ int journal_remote_add_raw_socket(RemoteServer *s, int fd) {
if (r < 0)
return r;
fd_ = -EBADF;
TAKE_FD(fd_);
s->active++;
return 0;
}
@@ -338,18 +361,12 @@ int journal_remote_server_init(
return 0;
}
#if HAVE_MICROHTTPD
static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
MHD_stop_daemon(d->daemon);
sd_event_source_unref(d->io_event);
sd_event_source_unref(d->timer_event);
free(d);
}
#endif
void journal_remote_server_destroy(RemoteServer *s) {
size_t i;
if (!s)
return;
#if HAVE_MICROHTTPD
hashmap_free_with_destructor(s->daemons, MHDDaemonWrapper_free);
#endif
@@ -389,6 +406,7 @@ int journal_remote_handle_raw_source(
* 0 if data is currently exhausted, negative on error.
*/
assert(s);
assert(fd >= 0 && fd < (ssize_t) MALLOC_ELEMENTSOF(s->sources));
source = s->sources[fd];
assert(source->importer.fd == fd);
@@ -424,9 +442,11 @@ int journal_remote_handle_raw_source(
static int dispatch_raw_source_until_block(sd_event_source *event,
void *userdata) {
RemoteSource *source = userdata;
RemoteSource *source = ASSERT_PTR(userdata);
int r;
assert(event);
/* Make sure event stays around even if source is destroyed */
sd_event_source_ref(event);
@@ -449,7 +469,7 @@ static int dispatch_raw_source_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
RemoteSource *source = userdata;
RemoteSource *source = ASSERT_PTR(userdata);
int r;
assert(source->event);
@@ -471,7 +491,7 @@ static int dispatch_raw_source_event(sd_event_source *event,
static int dispatch_blocking_source_event(sd_event_source *event,
void *userdata) {
RemoteSource *source = userdata;
RemoteSource *source = ASSERT_PTR(userdata);
return journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
}
@@ -485,6 +505,9 @@ static int accept_connection(
_cleanup_close_ int fd2 = -EBADF;
int r;
assert(addr);
assert(hostname);
log_debug("Accepting new %s connection on fd:%d", type, fd);
fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (fd2 < 0) {
@@ -530,7 +553,7 @@ static int dispatch_raw_connection_event(
uint32_t revents,
void *userdata) {
RemoteServer *s = userdata;
RemoteServer *s = ASSERT_PTR(userdata);
int fd2;
SocketAddress addr = {
.size = sizeof(union sockaddr_union),
+3
View File
@@ -20,6 +20,9 @@ struct MHDDaemonWrapper {
sd_event_source *io_event;
sd_event_source *timer_event;
};
MHDDaemonWrapper *MHDDaemonWrapper_free(MHDDaemonWrapper *d);
DEFINE_TRIVIAL_CLEANUP_FUNC(MHDDaemonWrapper*, MHDDaemonWrapper_free);
#endif
struct RemoteServer {
+10 -49
View File
@@ -518,45 +518,6 @@ static int perform_upload(Uploader *u) {
return update_cursor_state(u);
}
static int config_parse_path_or_ignore(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *n = NULL;
bool fatal = ltype;
char **s = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue))
goto finalize;
n = strdup(rvalue);
if (!n)
return log_oom();
if (streq(n, "-"))
goto finalize;
r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
if (r < 0)
return fatal ? -ENOEXEC : 0;
finalize:
return free_and_replace(*s, n);
}
static int parse_config(void) {
const ConfigTableItem items[] = {
{ "Upload", "URL", config_parse_string, CONFIG_PARSE_STRING_SAFE, &arg_url },
@@ -663,7 +624,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'u':
if (arg_url)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --url");
"Cannot use more than one --url=");
arg_url = optarg;
break;
@@ -671,7 +632,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_KEY:
if (arg_key)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --key");
"Cannot use more than one --key=");
arg_key = optarg;
break;
@@ -679,7 +640,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CERT:
if (arg_cert)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --cert");
"Cannot use more than one --cert=");
arg_cert = optarg;
break;
@@ -687,7 +648,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_TRUST:
if (arg_trust)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --trust");
"Cannot use more than one --trust=");
arg_trust = optarg;
break;
@@ -707,7 +668,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'M':
if (arg_machine)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --machine/-M");
"Cannot use more than one --machine=/-M");
arg_machine = optarg;
break;
@@ -715,7 +676,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'D':
if (arg_directory)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --directory/-D");
"Cannot use more than one --directory=/-D");
arg_directory = optarg;
break;
@@ -729,7 +690,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CURSOR:
if (arg_cursor)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --cursor/--after-cursor");
"Cannot use more than one --cursor=/--after-cursor=");
arg_cursor = optarg;
break;
@@ -737,7 +698,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_AFTER_CURSOR:
if (arg_cursor)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"cannot use more than one --cursor/--after-cursor");
"Cannot use more than one --cursor=/--after-cursor=");
arg_cursor = optarg;
arg_after_cursor = true;
@@ -770,11 +731,11 @@ static int parse_argv(int argc, char *argv[]) {
if (!arg_url)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Required --url/-u option missing.");
"Required --url=/-u option missing.");
if (!!arg_key != !!arg_cert)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Options --key and --cert must be used together.");
"Options --key= and --cert= must be used together.");
if (optind < argc && (arg_directory || arg_file || arg_machine || arg_journal_type))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+39
View File
@@ -196,3 +196,42 @@ int parse_socket_bind_item(
*port_min = mn;
return 0;
}
int config_parse_path_or_ignore(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *n = NULL;
bool fatal = ltype;
char **s = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue))
goto finalize;
n = strdup(rvalue);
if (!n)
return log_oom();
if (streq(n, "-"))
goto finalize;
r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
if (r < 0)
return fatal ? -ENOEXEC : 0;
finalize:
return free_and_replace(*s, n);
}
+12
View File
@@ -23,3 +23,15 @@ int parse_socket_bind_item(
int *ip_protocol,
uint16_t *nr_ports,
uint16_t *port_min);
int config_parse_path_or_ignore(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata);
+1
View File
@@ -6,3 +6,4 @@
# (at your option) any later version.
u systemd-journal-remote - "systemd Journal Remote"
u systemd-journal-upload - "systemd Journal Upload"
+7 -1
View File
@@ -57,7 +57,13 @@ curl -Lfs --header "Accept: text/event-stream" http://localhost:19531/entries |
# Same thing as journalctl --output=export
mkdir /tmp/remote-journal
curl -Lfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries | \
/usr/lib/systemd/systemd-journal-remote -o /tmp/remote-journal/system.journal --split-mode=none -
/usr/lib/systemd/systemd-journal-remote --output=/tmp/remote-journal/system.journal --split-mode=none -
journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE"
rm -rf /tmp/remote-journal/*
# Let's do the same thing again, but let systemd-journal-remote spawn curl itself
/usr/lib/systemd/systemd-journal-remote --url=http://localhost:19531/entries \
--output=/tmp/remote-journal/system.journal \
--split-mode=none
journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE"
rm -rf /tmp/remote-journal
+216
View File
@@ -0,0 +1,216 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# shellcheck disable=SC2016
set -eux
set -o pipefail
if [[ ! -x /usr/lib/systemd/systemd-journal-remote || ! -x /usr/lib/systemd/systemd-journal-upload ]]; then
echo "Built without systemd-journal-remote/upload support, skipping the test"
exit 0
fi
if ! command -v openssl >/dev/null; then
echo "openssl command not available, skipping the tests"
exit 0
fi
at_exit() {
set +e
systemctl stop systemd-journal-upload
systemctl stop systemd-journal-remote.{socket,service}
# Remove any remote journals on exit, so we don't try to export them together
# with the local journals, causing a mess
rm -rf /var/log/journal/remote
}
trap at_exit EXIT
TEST_MESSAGE="-= This is a test message $RANDOM =-"
TEST_TAG="$(systemd-id128 new)"
echo "$TEST_MESSAGE" | systemd-cat -t "$TEST_TAG"
journalctl --sync
/usr/lib/systemd/systemd-journal-remote --version
/usr/lib/systemd/systemd-journal-remote --help
/usr/lib/systemd/systemd-journal-upload --version
/usr/lib/systemd/systemd-journal-upload --help
# Generate a self-signed certificate for systemd-journal-remote
#
# Note: older OpenSSL requires a config file with some extra options, unfortunately
# Note2: /run here is used on purpose, since the systemd-journal-remote service uses PrivateTmp=yes
mkdir -p /run/systemd/journal-remote-tls
cat >/tmp/openssl.conf <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = CZ
L = Brno
O = Foo
OU = Bar
CN = localhost
EOF
openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 7 \
-config /tmp/openssl.conf \
-keyout /run/systemd/journal-remote-tls/key.pem \
-out /run/systemd/journal-remote-tls/cert.pem
chown -R systemd-journal-remote /run/systemd/journal-remote-tls
# Configure journal-upload to upload journals to journal-remote without client certificates
mkdir -p /run/systemd/journal-{remote,upload}.conf.d
cat >/run/systemd/journal-remote.conf.d/99-test.conf <<EOF
[Remote]
SplitMode=host
ServerKeyFile=/run/systemd/journal-remote-tls/key.pem
ServerCertificateFile=/run/systemd/journal-remote-tls/cert.pem
TrustedCertificateFile=-
EOF
cat >/run/systemd/journal-upload.conf.d/99-test.conf <<EOF
[Upload]
URL=https://localhost:19532
ServerKeyFile=-
ServerCertificateFile=-
TrustedCertificateFile=-
EOF
systemd-analyze cat-config systemd/journal-remote.conf
systemd-analyze cat-config systemd/journal-upload.conf
systemctl restart systemd-journal-remote.socket
systemctl restart systemd-journal-upload
timeout 15 bash -xec 'while ! systemctl -q is-active systemd-journal-remote.service; do sleep 1; done'
systemctl status systemd-journal-{remote,upload}
# It may take a bit until the whole journal is transferred
timeout 30 bash -xec "while ! journalctl --directory=/var/log/journal/remote --identifier='$TEST_TAG' --grep='$TEST_MESSAGE'; do sleep 1; done"
systemctl stop systemd-journal-upload
systemctl stop systemd-journal-remote.{socket,service}
rm -rf /var/log/journal/remote/*
# Now let's do the same, but with a full PKI setup
#
# journal-upload keeps the cursor of the last uploaded message, so let's send a fresh one
echo "$TEST_MESSAGE" | systemd-cat -t "$TEST_TAG"
journalctl --sync
mkdir /run/systemd/remote-pki
cat >/run/systemd/remote-pki/ca.conf <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = CZ
L = Brno
O = Foo
OU = Bar
CN = Test CA
EOF
cat >/run/systemd/remote-pki/client.conf <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = CZ
L = Brno
O = Foo
OU = Bar
CN = Test Client
EOF
cat >/run/systemd/remote-pki/server.conf <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = CZ
L = Brno
O = Foo
OU = Bar
CN = localhost
EOF
# Generate a dummy CA
openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 7 \
-config /run/systemd/remote-pki/ca.conf \
-keyout /run/systemd/remote-pki/ca.key \
-out /run/systemd/remote-pki/ca.crt
echo 01 >/run/systemd/remote-pki/ca.srl
# Generate a client key and signing request
openssl req -nodes -newkey rsa:2048 -sha256 \
-config /run/systemd/remote-pki/client.conf \
-keyout /run/systemd/remote-pki/client.key \
-out /run/systemd/remote-pki/client.csr
# Sign the request with the CA key
openssl x509 -req -days 7 \
-in /run/systemd/remote-pki/client.csr \
-CA /run/systemd/remote-pki/ca.crt \
-CAkey /run/systemd/remote-pki/ca.key \
-out /run/systemd/remote-pki/client.crt
# And do the same for the server
openssl req -nodes -newkey rsa:2048 -sha256 \
-config /run/systemd/remote-pki/server.conf \
-keyout /run/systemd/remote-pki/server.key \
-out /run/systemd/remote-pki/server.csr
openssl x509 -req -days 7 \
-in /run/systemd/remote-pki/server.csr \
-CA /run/systemd/remote-pki/ca.crt \
-CAkey /run/systemd/remote-pki/ca.key \
-out /run/systemd/remote-pki/server.crt
setfacl -R -m "u:systemd-journal-remote:rwX" /run/systemd/remote-pki
setfacl -R -m "u:systemd-journal-upload:rwX" /run/systemd/remote-pki
# Reconfigure journal-upload/journal remote with the new keys
cat >/run/systemd/journal-remote.conf.d/99-test.conf <<EOF
[Remote]
SplitMode=host
ServerKeyFile=/run/systemd/remote-pki/server.key
ServerCertificateFile=/run/systemd/remote-pki/server.crt
TrustedCertificateFile=/run/systemd/remote-pki/ca.crt
EOF
cat >/run/systemd/journal-upload.conf.d/99-test.conf <<EOF
[Upload]
URL=https://localhost:19532
ServerKeyFile=/run/systemd/remote-pki/client.key
ServerCertificateFile=/run/systemd/remote-pki/client.crt
TrustedCertificateFile=/run/systemd/remote-pki/ca.crt
EOF
systemd-analyze cat-config systemd/journal-remote.conf
systemd-analyze cat-config systemd/journal-upload.conf
systemctl restart systemd-journal-remote.socket
systemctl restart systemd-journal-upload
timeout 15 bash -xec 'while ! systemctl -q is-active systemd-journal-remote.service; do sleep 1; done'
systemctl status systemd-journal-{remote,upload}
# It may take a bit until the whole journal is transferred
timeout 30 bash -xec "while ! journalctl --directory=/var/log/journal/remote --identifier='$TEST_TAG' --grep='$TEST_MESSAGE'; do sleep 1; done"
systemctl stop systemd-journal-upload
systemctl stop systemd-journal-remote.{socket,service}
# Let's test if journal-remote refuses connection from journal-upload with invalid client certs
#
# We should end up with something like this:
# systemd-journal-remote[726]: Client is not authorized
# systemd-journal-upload[738]: Upload to https://localhost:19532/upload failed with code 401:
# systemd[1]: systemd-journal-upload.service: Main process exited, code=exited, status=1/FAILURE
# systemd[1]: systemd-journal-upload.service: Failed with result 'exit-code'.
#
cat >/run/systemd/journal-upload.conf.d/99-test.conf <<EOF
[Upload]
URL=https://localhost:19532
ServerKeyFile=/run/systemd/journal-remote-tls/key.pem
ServerCertificateFile=/run/systemd/journal-remote-tls/cert.pem
TrustedCertificateFile=/run/systemd/remote-pki/ca.crt
EOF
systemd-analyze cat-config systemd/journal-upload.conf
setfacl -R -m "u:systemd-journal-upload:rwX" /run/systemd/journal-remote-tls
systemctl restart systemd-journal-upload
timeout 10 bash -xec 'while [[ "$(systemctl show -P ActiveState systemd-journal-upload)" != failed ]]; do sleep 1; done'
(! systemctl status systemd-journal-upload)