Skip to content

Commit

Permalink
Add a new parameter to have an option to choose TCP socket creation (#…
Browse files Browse the repository at this point in the history
…142)

* Add a new parameter to have an option to choose TCP socket creation

---------

Co-authored-by: Madelen Andersson <[email protected]>
  • Loading branch information
deepikas20 and madelen-at-work authored Mar 26, 2024
1 parent e19b9b3 commit a25bcc4
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 37 deletions.
32 changes: 27 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The Docker ACAP application is available as a **signed** eap-file in [Releases][
> Meanwhile, the solution is to allow root to be able to install the Docker ACAP.
>
> On the web page of the device:
>
> 1. Go to the Apps page, toggle on `Allow root-privileged apps`.
> 1. Go to System -> Account page, under SSH accounts toggle off `Restrict root access` to be able to send the TLS certificates. Make sure to set the password of the `root` SSH user.
Expand Down Expand Up @@ -72,20 +73,36 @@ It's also possible to build and use a locally built image. See the

## Securing the Docker ACAP using TLS

The Docker ACAP can be run either unsecured or in TLS mode. The Docker ACAP uses
TLS as default. Use the "Use TLS" dropdown in the web interface to switch
between the two different modes. It's also possible to toggle this option by
calling the parameter management API in [VAPIX](https://www.axis.com/vapix-library/) and setting the
`root.dockerdwrapper.UseTLS` parameter to `yes` or `no`. The following commands would enable TLS:
The Docker Compose ACAP application can be run in either TLS mode or unsecured mode. The Docker Compose
ACAP application uses TLS mode by default. It is important to note that Dockerd will fail to start if
TCP socket or IPC socket parameters are not selected, one of these sockets must be set to `yes`.

Use the "Use TLS" and "TCP Socket" dropdowns in the web interface to switch between the
two different modes(yes/no). Whenever these settings change, the Docker daemon will automatically restart.
It's also possible to toggle this option by calling the parameter management API in
[VAPIX](https://www.axis.com/vapix-library/) and setting `root.dockerdwrapperwithcompose.UseTLS` and
`root.dockerdwrapperwithcompose.TCPSocket` parameters to `yes` or `no`.
The following commands would enable those parameters:

```sh
DEVICE_IP=<device ip>
DEVICE_PASSWORD='<password>'
```

Enable TLS:

```sh
curl -s --anyauth -u "root:$DEVICE_PASSWORD" \
"http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapper.UseTLS=yes"
```

Enable TCP Socket:

```sh
curl -s --anyauth -u "root:$DEVICE_PASSWORD" \
"http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.TCPSocket=yes"
```

Note that the dockerd service will be restarted every time TLS is activated or
deactivated. Running the ACAP using TLS requires some additional setup, see next chapter.
Running the ACAP without TLS requires no further setup.
Expand Down Expand Up @@ -202,6 +219,10 @@ See [Client key and certificate](#client-key-and-certificate) for an example
of how to remotely run docker commands on a device running a secured Docker ACAP
using TLS.

The application can provide a TCP socket if the TCP Socket setting is set to `yes` and an IPC socket
if the IPC Socket setting is set to `yes`. Please be aware that at least one of these sockets must be
selected for the application to start.

## Building the Docker ACAP

To build the Docker ACAP use docker buildx with the provided Dockerfile:
Expand All @@ -214,6 +235,7 @@ docker buildx build --file Dockerfile --tag docker-acap:<ARCH> --build-arg ACAPA
where `<ARCH>` is either `armv7hf` or `aarch64`.

To extract the Docker ACAP eap-file use docker cp to copy it to a `build` folder:

```sh
docker cp "$(docker create "docker-acap:<ARCH>")":/opt/app/ ./build
```
Expand Down
97 changes: 65 additions & 32 deletions app/dockerdwrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
struct settings {
char *data_root;
bool use_tls;
bool use_tcp_socket;
bool use_ipc_socket;
};

Expand All @@ -55,7 +56,10 @@ static const char *dockerd_path_on_sd_card =
"/var/spool/storage/SD_DISK/dockerd";

// All ax_parameters the acap has
static const char *ax_parameters[] = {"IPCSocket", "SDCardSupport", "UseTLS"};
static const char *ax_parameters[] = {"IPCSocket",
"SDCardSupport",
"TCPSocket",
"UseTLS"};

static const char *tls_cert_path = "/usr/local/packages/dockerdwrapper/";

Expand Down Expand Up @@ -350,6 +354,19 @@ get_and_verify_tls_selection(bool *use_tls_ret)
return return_value;
}

/**
* @brief Gets and verifies the TCPSocket selection
*
* @param use_tcp_socket_ret selection to be updated.
* @return True if successful, false otherwise.
*/
static gboolean
get_tcp_socket_selection(bool *use_tcp_socket_ret)
{
*use_tcp_socket_ret = is_parameter_yes("TCPSocket");
return true;
}

/**
* @brief Gets and verifies the IPCSocket selection
*
Expand All @@ -374,6 +391,10 @@ read_settings(struct settings *settings)
syslog(LOG_ERR, "Failed to verify tls selection");
return false;
}
if (!get_tcp_socket_selection(&settings->use_tcp_socket)) {
syslog(LOG_ERR, "Failed to get tcp socket selection");
return false;
}
if (!get_ipc_socket_selection(&settings->use_ipc_socket)) {
syslog(LOG_ERR, "Failed to get ipc socket selection");
return false;
Expand All @@ -388,6 +409,7 @@ start_dockerd(const struct settings *settings)
{
const char *data_root = settings->data_root;
const bool use_tls = settings->use_tls;
const bool use_tcp_socket = settings->use_tcp_socket;
const bool use_ipc_socket = settings->use_ipc_socket;

GError *error = NULL;
Expand All @@ -411,53 +433,64 @@ start_dockerd(const struct settings *settings)

g_strlcpy(msg, "Starting dockerd", msg_len);

if (use_tls) {
const char *ca_path = "/usr/local/packages/dockerdwrapper/ca.pem";
const char *cert_path =
"/usr/local/packages/dockerdwrapper/server-cert.pem";
const char *key_path = "/usr/local/packages/dockerdwrapper/server-key.pem";
if (!use_ipc_socket && !use_tcp_socket) {
syslog(LOG_ERR,
"At least one of IPC socket or TCP socket must be set to \"yes\". "
"dockerd will not be started.");
goto end;
}

if (use_ipc_socket) {
g_strlcat(msg, " with IPC socket and", msg_len);
args_offset += g_snprintf(args + args_offset,
args_len - args_offset,
" %s %s %s %s %s %s %s %s",
"-H tcp://0.0.0.0:2376",
"--tlsverify",
"--tlscacert",
ca_path,
"--tlscert",
cert_path,
"--tlskey",
key_path);

g_strlcat(msg, " in TLS mode", msg_len);
" -H unix:///var/run/docker.sock");
} else {
g_strlcat(msg, " without IPC socket and", msg_len);
}

if (use_tcp_socket) {
g_strlcat(msg, " with TCP socket", msg_len);
const uint port = use_tls ? 2376 : 2375;
args_offset += g_snprintf(args + args_offset,
args_len - args_offset,
" %s %s",
"-H tcp://0.0.0.0:2375",
"--tls=false");

g_strlcat(msg, " in unsecured mode", msg_len);
" -H tcp://0.0.0.0:%d",
port);
if (use_tls) {
const char *ca_path = "/usr/local/packages/dockerdwrapper/ca.pem";
const char *cert_path =
"/usr/local/packages/dockerdwrapper/server-cert.pem";
const char *key_path =
"/usr/local/packages/dockerdwrapper/server-key.pem";
args_offset += g_snprintf(args + args_offset,
args_len - args_offset,
" %s %s %s %s %s %s %s",
"--tlsverify",
"--tlscacert",
ca_path,
"--tlscert",
cert_path,
"--tlskey",
key_path);
g_strlcat(msg, " in TLS mode", msg_len);
} else {
args_offset += g_snprintf(
args + args_offset, args_len - args_offset, " --tls=false");
g_strlcat(msg, " in unsecured mode", msg_len);
}
} else {
g_strlcat(msg, " without TCP socket", msg_len);
}

g_autofree char *data_root_msg = g_strdup_printf(
" using %s as storage", data_root ? data_root : "/var/lib/docker");
" using %s as storage.", data_root ? data_root : "/var/lib/docker");
g_strlcat(msg, data_root_msg, msg_len);
if (data_root)
args_offset += g_snprintf(args + args_offset,
args_len - args_offset,
" --data-root %s",
data_root);

if (use_ipc_socket) {
g_strlcat(msg, " with IPC socket.", msg_len);
args_offset += g_snprintf(args + args_offset,
args_len - args_offset,
" -H unix:///var/run/docker.sock");
} else {
g_strlcat(msg, " without IPC socket.", msg_len);
}

// Log startup information to syslog.
syslog(LOG_INFO, "%s", msg);

Expand Down
5 changes: 5 additions & 0 deletions app/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
"default": "yes",
"type": "enum:no|No, yes|Yes"
},
{
"name": "TCPSocket",
"default": "yes",
"type": "enum:no|No, yes|Yes"
},
{
"name": "IPCSocket",
"default": "no",
Expand Down

0 comments on commit a25bcc4

Please sign in to comment.