summaryrefslogtreecommitdiffstats
path: root/node-admin/scripts/setup-docker.sh
blob: 3e4b10dbd7464f2455efb73b2cafdfa4a07528a0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/bin/bash
# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

# WARNING: Please double-check with the documentation in node-admin/README*
# whether these commands are in fact correct. If they are, this saves a bunch
# of typing...
#
# See HelpAndExit below for usage.

set -ex

declare DAYS_VALID=3650

# Note regarding the file names: Some are renamed from what you get from
# following the recipe in the docker documentation.  Here, we've used
# underscores exclusively, never dashes. Some files have been renamed for
# explicitness, clarity and consistency (e.g. 'key' is renamed 'client_key').
declare CERTS_DIR=~/.docker-certs
declare CA_FILE="$CERTS_DIR"/ca_cert.pem
declare CA_KEY_FILE="$CERTS_DIR"/ca_key.pem
declare CLIENT_CERT_FILE="$CERTS_DIR"/client_cert.pem
declare CLIENT_KEY_FILE="$CERTS_DIR"/client_key.pem
declare SERVER_CERT_FILE="$CERTS_DIR"/server_cert.pem
declare SERVER_KEY_FILE="$CERTS_DIR"/server_key.pem

declare GROUP=users
declare YAHOO_GROUP="$GROUP"

function HelpAndExit {
    cat <<EOF
Usage: ${0##*/} <command>...
Setup Docker.

Commands:
  all             Setup docker home and TLS certificates/keys.
                  Same as following commands: home certs
  certs           Generate and install TLS keys.
                  Same as following commands: generate-certs install-certs
  generate-certs  Generate TLS-related certificates and keys to
                    $CERTS_DIR
  help            Print this message.
  install-certs   Install TLS-related certificates and keys in
                    $CERTS_DIR
                  to /etc/dockercert_{daemon,cli,container}.
  home            Add docker user and make symbolic links from Docker dirs in
                  /var to dirs below ~docker.
EOF

    exit 0
}

function GenerateCertificates {
    rm -rf "$CERTS_DIR"
    mkdir -p "$CERTS_DIR"

    # Generate CA private and public keys
    echo "We're about to generate a CA key, please use a secure password."
    echo "You will be prompted for this password many times in what follows..."
    openssl genrsa -aes256 -out "$CA_KEY_FILE" 4096
    openssl req -new -x509 -days "$DAYS_VALID" -key "$CA_KEY_FILE" -sha256 \
            -out "$CA_FILE"

    # Generate server key and certificate signing request (CSR)
    openssl genrsa -out "$SERVER_KEY_FILE" 4096
    local server_csr_file="$CERTS_DIR"/server.csr
    openssl req -subj "/CN=$HOSTNAME" -sha256 -new -key "$SERVER_KEY_FILE" \
            -out "$server_csr_file"

    # Sign server's public key with CA
    local server_config_file="$CERTS_DIR"/server.cnf
    echo "subjectAltName = IP:127.0.0.1" > "$server_config_file"
    openssl x509 -req -days "$DAYS_VALID" -sha256 -in "$server_csr_file" \
            -CA "$CA_FILE" -CAkey "$CA_KEY_FILE" -CAcreateserial \
            -out "$SERVER_CERT_FILE" -extfile "$server_config_file"

    # Generate client key and certificate signing request (CSR)
    openssl genrsa -out "$CLIENT_KEY_FILE" 4096
    local client_csr_file="$CERTS_DIR"/client.csr
    openssl req -subj '/CN=client' -new -key "$CLIENT_KEY_FILE" \
            -out "$client_csr_file"

    # Sign client's public key with CA
    local client_config_file="$CERTS_DIR"/client.cnf
    echo extendedKeyUsage = clientAuth > "$client_config_file"
    openssl x509 -req -days "$DAYS_VALID" -sha256 -in "$client_csr_file" \
            -CA "$CA_FILE" -CAkey "$CA_KEY_FILE" -CAcreateserial \
            -out "$CLIENT_CERT_FILE" -extfile "$client_config_file"

    # CSR and config files no longer needed
    rm "$client_csr_file" "$server_csr_file"
    rm "$server_config_file" "$client_config_file"

    # Avoid accidental writes
    chmod 0400 "$CA_KEY_FILE" "$CLIENT_KEY_FILE" "$SERVER_KEY_FILE"
    chmod 0444 "$CA_FILE" "$SERVER_CERT_FILE" "$CLIENT_CERT_FILE"
}

function InstallCertificates {
    # The files you end up with after GenerateKeys will be used by three
    # parties: The docker daemon, the docker CLI, and the docker client in Node
    # Admin. None of these parties need (nor should they have) access to all
    # these files. Also, the three parties will run as different users. Since
    # these files should not be world-readable, one solution is to create
    # separate directories for the three usages, so each directory may contain
    # only the needed files, with the correct owner and permissions.

    sudo mkdir -p /etc/dockercert_daemon
    sudo chown yahoo:users /etc/dockercert_daemon
    sudo cp "$CA_FILE" "$SERVER_CERT_FILE" "$SERVER_KEY_FILE" /etc/dockercert_daemon
    sudo chown root:root /etc/dockercert_daemon/*

    # The docker client looks for files with certain names (you can only
    # configure the path to the directory containing the files), so the
    # "original" file names are used.
    sudo mkdir -p /etc/dockercert_cli
    sudo chown yahoo:users /etc/dockercert_cli
    sudo cp "$CA_FILE" /etc/dockercert_cli/ca.pem
    sudo cp "$CLIENT_CERT_FILE" /etc/dockercert_cli/cert.pem
    sudo cp "$CLIENT_KEY_FILE" /etc/dockercert_cli/key.pem
    sudo chown $USER:$GROUP /etc/dockercert_cli/*

    sudo mkdir -p /etc/dockercert_container
    sudo chown yahoo:$YAHOO_GROUP /etc/dockercert_container
    # These filenames must match the config given in
    # src/main/application/services.xml.
    sudo cp "$CA_FILE" "$CLIENT_CERT_FILE" "$CLIENT_KEY_FILE" /etc/dockercert_container
    sudo chown yahoo:$YAHOO_GROUP /etc/dockercert_container/*

    echo "Note: Consider reloading & restarting the docker daemon to pick up"
    echo "the new certificates and keys:"
    echo "  sudo systemctl daemon-reload"
    echo "  sudo systemctl restart docker"
}

function SetupDockerHome {
    # Assume an error means the docker user already exists
    sudo useradd -g docker docker || true

    sudo mkdir -p ~docker/lib ~docker/run
    sudo chmod +rx ~docker ~docker/lib ~docker/run
    sudo systemctl stop docker
    sudo rm -rf /var/{run,lib}/docker
    sudo ln -s ~docker/run /var/run/docker
    sudo ln -s ~docker/lib /var/lib/docker
    sudo systemctl daemon-reload
    sudo systemctl restart docker
}

function Main {
    # Prime sudo
    sudo true

    if (($# == 0))
    then
        HelpAndExit
    fi

    local command
    for command in "$@"
    do
        case "$command" in
            all) Main home certs ;;
            certs)
                GenerateCertificates
                InstallCertificates
                ;;
            generate-certs) GenerateCertificates ;;
            help) HelpAndExit ;;
            home) SetupDockerHome ;;
            install-certs) InstallCertificates ;;
            *) Fail "Unknown command '$command'" ;;
        esac
    done
}

Main "$@"