Compare commits

...

18 Commits

Author SHA1 Message Date
c1ee146f0d v1.1.0 2019-05-07 14:38:17 +03:00
9ad92596b9 Merge pull request #49 from balena-io/48-s3-credential-changes
s3: Update to latest version with credentials
2019-05-07 12:36:26 +01:00
56de2d20bb s3: Update to latest version with credentials
Credentials for S3 can now be specified using the
following docker-compose based envvars:

* S3_MINIO_ACCESS_KEY
* S3_MINIO_SECRET_KEY

Connects-to: #48
Change-type: minor
Signed-off-by: Heds Simons <heds@balena.io>
2019-05-07 11:18:48 +01:00
290c90c262 v1.0.2 2019-04-18 15:30:38 +03:00
98b6100fed Merge pull request #45 from roman-mazur/roman/fix-build
scripts: Handle missing coreutils on Mac
2019-04-18 15:28:19 +03:00
e1bfb7f7b0 scripts: Handle missing coreutils on Mac
For convenience, also add instructions what to install.
Tha change also addresses invalid usage of 'local' outside of a function.

Change-type: patch
Signed-off-by: Roman Mazur <mazur.roman@gmail.com>
2019-04-16 18:05:16 +03:00
35ab5300e6 v1.0.1 2019-03-20 11:24:21 +02:00
fd031ad3a4 Merge pull request #42 from balena-io/prevent-root-ca-signing-vpn-ca
vpn: Remove BALENA_ROOT_CA from the VPN trust chain
2019-03-20 09:22:11 +00:00
95d53993bc vpn: Remove BALENA_ROOT_CA from the VPN trust chain
The VPN CA shouldn't need to be signed by the same CA that the HAproxy service
certificate is signed by. By removing this chain we are able to use a
different CA for the HTTPS services without impacting on the VPN service.

Change-type: patch
Signed-off-by: Rich Bayliss <rich@balena.io>
2019-03-20 09:13:19 +00:00
1721728794 v1.0.0 2019-03-15 17:29:55 +02:00
061440f109 Merge pull request #43 from balena-io/pin-service-tags
tags: Pin the image tags for the service stack
2019-03-15 15:28:08 +00:00
2f0fb27145 tags: Pin the image tags for the service stack
In order to have concrete releases of openBalena we should pin each
service to a given version. This PR is the start of this and marks
the first version of openBalena with known service tags.

Change-type: major
Signed-off-by: Rich Bayliss <rich@balena.io>
2019-03-15 15:14:57 +00:00
210bdcda37 v0.2.2 2019-03-08 15:44:55 +02:00
fac66040c8 Merge pull request #39 from balena-io/add-codeowners
codeowners: Add CODEOWNERS file
2019-03-08 13:42:59 +00:00
85a69c1ef1 codeowners: Add CODEOWNERS file
Add a CODEOWNERS file which includes the main repo owners.

Change-type: patch
Signed-off-by: Rich Bayliss <rich@balena.io>
2019-03-08 13:38:49 +00:00
e37a61e5f0 v0.2.1 2019-03-08 14:31:30 +02:00
0fc85ff5b6 Merge pull request #38 from balena-io/add-acme-support
certs: Add support for an ACME certificate provider
2019-03-08 12:29:44 +00:00
99dd615e55 certs: Add support for an ACME certificate provider
Add a service which will acquire certificates from an ACME cert
provider, such as LetsEncrypt (), to allow an openBalena instance
to use a publicly trusted certificate instead of the self-signed
one it wil generate on setup.

Change-type: patch
Signed-off-by: Rich Bayliss <rich@balena.io>
2019-03-08 12:23:46 +00:00
18 changed files with 430 additions and 53 deletions

2
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,2 @@
# Main repo owners:
* @dfunckt @richbayliss

View File

@ -4,6 +4,36 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).
# v1.1.0
## (2019-05-07)
* s3: Update to latest version with credentials [Heds Simons]
# v1.0.2
## (2019-04-17)
* scripts: Handle missing coreutils on Mac [Roman Mazur]
# v1.0.1
## (2019-03-20)
* vpn: Remove BALENA_ROOT_CA from the VPN trust chain [Rich Bayliss]
# v1.0.0
## (2019-03-15)
* tags: Pin the image tags for the service stack [Rich Bayliss]
# v0.2.2
## (2019-03-08)
* codeowners: Add CODEOWNERS file [Rich Bayliss]
# v0.2.1
## (2019-03-08)
* certs: Add support for an ACME certificate provider [Rich Bayliss]
# v0.2.0
## (2019-01-25)

View File

@ -1 +1 @@
0.2.0
1.1.0

20
cert-provider/Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM alpine
EXPOSE 80
WORKDIR /usr/src/app
VOLUME [ "/usr/src/app/certs" ]
RUN apk add --update bash curl git openssl ncurses socat
RUN git clone https://github.com/Neilpang/acme.sh.git && \
cd acme.sh && \
git checkout 08357e3cb0d80c84bdaf3e42ce0e439665387f57 . && \
./acme.sh --install \
--cert-home /usr/src/app/certs
COPY entry.sh /entry.sh
COPY cert-provider.sh ./cert-provider.sh
COPY fake-le-bundle.pem ./
ENTRYPOINT [ "/entry.sh" ]
CMD [ "/usr/src/app/cert-provider.sh" ]

181
cert-provider/cert-provider.sh Executable file
View File

@ -0,0 +1,181 @@
#!/bin/bash
# the acme.sh client script, installed via Git in the Dockerfile...
ACME_BIN="$(realpath ~/.acme.sh/acme.sh)"
# the path to a bundle of certs to verify a LetsEncrypt staging certificate until Apr 2036...
ACME_STAGING_CA="/usr/src/app/fake-le-bundle.pem"
# the path to a file which stores the last successful mode of certificate we acquired...
ACME_MODE_FILE="/usr/src/app/certs/last_run_mode"
# colour output helpers...
reset=$(tput -T xterm sgr0)
red=$(tput -T xterm setaf 1)
green=$(tput -T xterm setaf 2)
yellow=$(tput -T xterm setaf 3)
blue=$(tput -T xterm setaf 4)
logError() {
echo "${red}[Error]${reset} $1"
}
logWarn() {
echo "${yellow}[Warn]${reset} $1"
}
logInfo() {
echo "${blue}[Info]${reset} $1"
}
logSuccess() {
echo "${green}[Success]${reset} $1"
}
logErrorAndStop() {
logError "$1 [Stopping]"
while true; do
# do nothing forever...
sleep 60
done
}
retryWithDelay() {
RETRIES=${2:-3}
DELAY=${3:-5}
local ATTEMPT=0
while [ $RETRIES -gt $ATTEMPT ]; do
let "ATTEMPT++"
if $1; then
return $?
fi
echo "($ATTEMPT/$RETRIES) Retrying in ${DELAY} seconds..."
sleep $DELAY
done
return 1
}
waitForOnline() {
ADDRESS="${1,,}"
logInfo "Waiting for ${ADDRESS} to be available via HTTP..."
retryWithDelay "curl --output /dev/null --silent --head --fail http://${ADDRESS}" 6 5
}
isUsingStagingCert() {
HOST="${1,,}"
echo "" | openssl s_client -host "$HOST" -port 443 -showcerts 2>/dev/null | awk '/BEGIN CERT/ {p=1} ; p==1; /END CERT/ {p=0}' | openssl verify -CAfile "$ACME_STAGING_CA" > /dev/null 2>&1
}
pre-flight() {
case "$ACTIVE" in
"true"|"yes")
;;
*)
logError "ACTIVE variable is not enabled. Value should be \"true\" or \"yes\" to continue."
return 1
;;
esac
if [ -z "$DOMAINS" ]; then
logError "DOMAINS must be set. Value should be a comma-delimited string of domains."
return 1
else
IFS=, read -r -a ACME_DOMAINS <<< "$DOMAINS"
IFS=' ' read -r -a ACME_DOMAIN_ARGS <<< "${ACME_DOMAINS[@]/#/-d }"
fi
if [ -z "$VALIDATION" ]; then
logInfo "VALIDATION not set. Using default: http-01"
VALIDATION="http-01"
else
case "$VALIDATION" in
"http-01")
logInfo "Using validation method: $VALIDATION"
;;
*)
logError "VALIDATION is invalid. Use a valid value: http-01"
return 1
;;
esac
fi
if [ -z "$OUTPUT_PEM" ]; then
logError "OUTPUT_PEM must be set. Value should be the path to install your certificate to."
return 1
fi
}
waitToSeeStagingCert() {
logInfo "Waiting for ${ACME_DOMAINS[0]} to use a staging certificate..."
retryWithDelay "isUsingStagingCert ${ACME_DOMAINS[0]}" 3 5
}
lastAcquiredCertFor() {
ACME_MODE="${1:-none}"
ACME_LAST_MODE="$(cat $ACME_MODE_FILE || echo '')"
logInfo "Last acquired certificate for ${ACME_LAST_MODE^^}"
[ "${ACME_LAST_MODE,,}" == "${ACME_MODE,,}" ]
}
acquireCertificate() {
ACME_MODE="${1:-staging}"
ACME_FORCE="${2:-false}"
ACME_OPTS=()
if [ "${ACME_FORCE,,}" == "true" ];then ACME_OPTS+=("--force"); fi
case "$ACME_MODE" in
"production")
logInfo "Using PRODUCTION mode"
;;
*)
logInfo "Using STAGING mode"
ACME_OPTS+=("--staging")
;;
esac
case "$VALIDATION" in
"http-01")
ACME_OPTS+=("--standalone")
;;
*)
logError "VALIDATION is invalid. Use a valid value: http-01"
return 1
;;
esac
if ! waitForOnline "${ACME_DOMAINS[0]}"; then
logError "Unable to access site over HTTP"
return 1
fi
logInfo "Issuing certificates..."
"$ACME_BIN" --issue "${ACME_OPTS[@]}" "${ACME_DOMAIN_ARGS[@]}"
logInfo "Installing certificates..." && \
"$ACME_BIN" --install-cert "${ACME_DOMAIN_ARGS[@]}" \
--cert-file /tmp/cert.pem \
--key-file /tmp/key.pem \
--fullchain-file /tmp/fullchain.pem \
--reloadcmd "cat /tmp/fullchain.pem /tmp/key.pem > $OUTPUT_PEM" && \
echo "${ACME_MODE}" > "${ACME_MODE_FILE}"
}
pre-flight || logErrorAndStop "Unable to continue due to misconfiguration. See errors above."
waitForOnline "${ACME_DOMAINS[0]}" || logErrorAndStop "Unable to access ${ACME_DOMAINS[0]} on port 80. This is needed for certificate validation."
if ! lastAcquiredCertFor "production"; then
acquireCertificate "staging" || logErrorAndStop "Unable to acquire a staging certificate."
waitToSeeStagingCert || logErrorAndStop "Unable to detect certificate change over. Cannot issue a production certificate."
acquireCertificate "production" "true" || logErrorAndStop "Unable to acquire a production certificate."
fi
logSuccess "Done!"
logInfo "Running cron..."
crond -f -d 7

3
cert-provider/entry.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
exec "$@"

View File

@ -0,0 +1,56 @@
-----BEGIN CERTIFICATE-----
MIIFATCCAumgAwIBAgIRAKc9ZKBASymy5TLOEp57N98wDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDMyMzIyNTM0NloXDTM2
MDMyMzIyNTM0NlowGjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMIICIjANBgkq
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+pYHvQw5iU3v2b3iNuYNKYgsWD6KU7aJ
diddtZQxSWYzUI3U0I1UsRPTxnhTifs/M9NW4ZlV13ZfB7APwC8oqKOIiwo7IwlP
xg0VKgyz+kT8RJfYr66PPIYP0fpTeu42LpMJ+CKo9sbpgVNDZN2z/qiXrRNX/VtG
TkPV7a44fZ5bHHVruAxvDnylpQxJobtCBWlJSsbIRGFHMc2z88eUz9NmIOWUKGGj
EmP76x8OfRHpIpuxRSCjn0+i9+hR2siIOpcMOGd+40uVJxbRRP5ZXnUFa2fF5FWd
O0u0RPI8HON0ovhrwPJY+4eWKkQzyC611oLPYGQ4EbifRsTsCxUZqyUuStGyp8oa
aoSKfF6X0+KzGgwwnrjRTUpIl19A92KR0Noo6h622OX+4sZiO/JQdkuX5w/HupK0
A0M0WSMCvU6GOhjGotmh2VTEJwHHY4+TUk0iQYRtv1crONklyZoAQPD76hCrC8Cr
IbgsZLfTMC8TWUoMbyUDgvgYkHKMoPm0VGVVuwpRKJxv7+2wXO+pivrrUl2Q9fPe
Kk055nJLMV9yPUdig8othUKrRfSxli946AEV1eEOhxddfEwBE3Lt2xn0hhiIedbb
Ftf/5kEWFZkXyUmMJK8Ra76Kus2ABueUVEcZ48hrRr1Hf1N9n59VbTUaXgeiZA50
qXf2bymE6F8CAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFMEmdKSKRKDm+iAo2FwjmkWIGHngMA0GCSqGSIb3DQEBCwUA
A4ICAQBCPw74M9X/Xx04K1VAES3ypgQYH5bf9FXVDrwhRFSVckria/7dMzoF5wln
uq9NGsjkkkDg17AohcQdr8alH4LvPdxpKr3BjpvEcmbqF8xH+MbbeUEnmbSfLI8H
sefuhXF9AF/9iYvpVNC8FmJ0OhiVv13VgMQw0CRKkbtjZBf8xaEhq/YqxWVsgOjm
dm5CAQ2X0aX7502x8wYRgMnZhA5goC1zVWBVAi8yhhmlhhoDUfg17cXkmaJC5pDd
oenZ9NVhW8eDb03MFCrWNvIh89DDeCGWuWfDltDq0n3owyL0IeSn7RfpSclpxVmV
/53jkYjwIgxIG7Gsv0LKMbsf6QdBcTjhvfZyMIpBRkTe3zuHd2feKzY9lEkbRvRQ
zbh4Ps5YBnG6CKJPTbe2hfi3nhnw/MyEmF3zb0hzvLWNrR9XW3ibb2oL3424XOwc
VjrTSCLzO9Rv6s5wi03qoWvKAQQAElqTYRHhynJ3w6wuvKYF5zcZF3MDnrVGLbh1
Q9ePRFBCiXOQ6wPLoUhrrbZ8LpFUFYDXHMtYM7P9sc9IAWoONXREJaO08zgFtMp4
8iyIYUyQAbsvx8oD2M8kRvrIRSrRJSl6L957b4AFiLIQ/GgV2curs0jje7Edx34c
idWw1VrejtwclobqNMVtG3EiPUIpJGpbMcJgbiLSmKkrvQtGng==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEqzCCApOgAwIBAgIRAIvhKg5ZRO08VGQx8JdhT+UwDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDUyMzIyMDc1OVoXDTM2
MDUyMzIyMDc1OVowIjEgMB4GA1UEAwwXRmFrZSBMRSBJbnRlcm1lZGlhdGUgWDEw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtWKySDn7rWZc5ggjz3ZB0
8jO4xti3uzINfD5sQ7Lj7hzetUT+wQob+iXSZkhnvx+IvdbXF5/yt8aWPpUKnPym
oLxsYiI5gQBLxNDzIec0OIaflWqAr29m7J8+NNtApEN8nZFnf3bhehZW7AxmS1m0
ZnSsdHw0Fw+bgixPg2MQ9k9oefFeqa+7Kqdlz5bbrUYV2volxhDFtnI4Mh8BiWCN
xDH1Hizq+GKCcHsinDZWurCqder/afJBnQs+SBSL6MVApHt+d35zjBD92fO2Je56
dhMfzCgOKXeJ340WhW3TjD1zqLZXeaCyUNRnfOmWZV8nEhtHOFbUCU7r/KkjMZO9
AgMBAAGjgeMwgeAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw
HQYDVR0OBBYEFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHoGCCsGAQUFBwEBBG4wbDA0
BggrBgEFBQcwAYYoaHR0cDovL29jc3Auc3RnLXJvb3QteDEubGV0c2VuY3J5cHQu
b3JnLzA0BggrBgEFBQcwAoYoaHR0cDovL2NlcnQuc3RnLXJvb3QteDEubGV0c2Vu
Y3J5cHQub3JnLzAfBgNVHSMEGDAWgBTBJnSkikSg5vogKNhcI5pFiBh54DANBgkq
hkiG9w0BAQsFAAOCAgEABYSu4Il+fI0MYU42OTmEj+1HqQ5DvyAeyCA6sGuZdwjF
UGeVOv3NnLyfofuUOjEbY5irFCDtnv+0ckukUZN9lz4Q2YjWGUpW4TTu3ieTsaC9
AFvCSgNHJyWSVtWvB5XDxsqawl1KzHzzwr132bF2rtGtazSqVqK9E07sGHMCf+zp
DQVDVVGtqZPHwX3KqUtefE621b8RI6VCl4oD30Olf8pjuzG4JKBFRFclzLRjo/h7
IkkfjZ8wDa7faOjVXx6n+eUQ29cIMCzr8/rNWHS9pYGGQKJiY2xmVC9h12H99Xyf
zWE9vb5zKP3MVG6neX1hSdo7PEAb9fqRhHkqVsqUvJlIRmvXvVKTwNCP3eCjRCCI
PTAvjV+4ni786iXwwFYNz8l3PmPLCyQXWGohnJ8iBm+5nk7O2ynaPVW0U2W+pt2w
SVuvdDM5zGv2f9ltNWUiYZHJ1mmO97jSY/6YfdOUH66iRtQtDkHBRdkNBsMbD+Em
2TgBldtHNSJBfB3pm9FblgOcJ0FSWcUDWJ7vO0+NTXlgrRofRT6pVywzxVo6dND0
WzYlTWeUVsO40xJqhgUQRER9YLOLxJ0O6C8i0xFxAMKOtSdodMB3RIwt7RFQ0uyt
n5Z5MqkYhlMI3J1tPRTp1nEt9fyGspBOO05gi148Qasp+3N+svqKomoQglNoAxU=
-----END CERTIFICATE-----

View File

@ -1,10 +1,12 @@
version: '2.1'
version: "2.1"
volumes:
db:
registry:
s3:
redis:
certs: {}
cert-provider: {}
db: {}
redis: {}
registry: {}
s3: {}
services:
api:
@ -20,7 +22,7 @@ services:
API_VPN_SERVICE_API_KEY: ${OPENBALENA_API_VPN_SERVICE_API_KEY}
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
COOKIE_SESSION_SECRET: ${OPENBALENA_COOKIE_SESSION_SECRET}
DB_HOST: db.${OPENBALENA_HOST_NAME}
DB_HOST: db
DB_PASSWORD: docker
DB_PORT: 5432
DB_USER: docker
@ -36,10 +38,10 @@ services:
JSON_WEB_TOKEN_EXPIRY_MINUTES: 10080
JSON_WEB_TOKEN_SECRET: ${OPENBALENA_JWT_SECRET}
MIXPANEL_TOKEN: __unused__
PRODUCTION_MODE: '${OPENBALENA_PRODUCTION_MODE}'
PRODUCTION_MODE: "${OPENBALENA_PRODUCTION_MODE}"
PUBNUB_PUBLISH_KEY: __unused__
PUBNUB_SUBSCRIBE_KEY: __unused__
REDIS_HOST: redis.${OPENBALENA_HOST_NAME}
REDIS_HOST: redis
REDIS_PORT: 6379
REGISTRY2_HOST: registry.${OPENBALENA_HOST_NAME}
REGISTRY_HOST: registry.${OPENBALENA_HOST_NAME}
@ -49,7 +51,7 @@ services:
TOKEN_AUTH_CERT_KEY: ${OPENBALENA_TOKEN_AUTH_KEY}
TOKEN_AUTH_CERT_KID: ${OPENBALENA_TOKEN_AUTH_KID}
TOKEN_AUTH_CERT_PUB: ${OPENBALENA_TOKEN_AUTH_PUB}
TOKEN_AUTH_JWT_ALGO: 'ES256'
TOKEN_AUTH_JWT_ALGO: "ES256"
VPN_HOST: vpn.${OPENBALENA_HOST_NAME}
VPN_PORT: 443
VPN_SERVICE_API_KEY: ${OPENBALENA_VPN_SERVICE_API_KEY}
@ -94,10 +96,10 @@ services:
BALENA_API_HOST: api.${OPENBALENA_HOST_NAME}
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
BALENA_VPN_PORT: 443
PRODUCTION_MODE: '${OPENBALENA_PRODUCTION_MODE}'
PRODUCTION_MODE: "${OPENBALENA_PRODUCTION_MODE}"
RESIN_VPN_GATEWAY: 10.2.0.1
SENTRY_DSN:
VPN_HAPROXY_USEPROXYPROTOCOL: 'true'
VPN_HAPROXY_USEPROXYPROTOCOL: "true"
VPN_OPENVPN_CA_CRT: ${OPENBALENA_VPN_CA}
VPN_OPENVPN_SERVER_CRT: ${OPENBALENA_VPN_SERVER_CRT}
VPN_OPENVPN_SERVER_DH: ${OPENBALENA_VPN_SERVER_DH}
@ -115,10 +117,13 @@ services:
s3:
extends:
file: ./common.yml
service: system
service: component
image: balena/open-balena-s3:${OPENBALENA_S3_VERSION_TAG:-master}
volumes:
- s3:/export
environment:
S3_MINIO_ACCESS_KEY: abcdef1234
S3_MINIO_SECRET_KEY: "1234567890"
redis:
extends:
@ -135,11 +140,12 @@ services:
build: ../haproxy
depends_on:
- api
- registry
- vpn
- cert-provider
- db
- s3
- redis
- registry
- vpn
ports:
- "80:80"
- "443:443"
@ -162,3 +168,15 @@ services:
BALENA_HAPROXY_KEY: ${OPENBALENA_ROOT_KEY}
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
HAPROXY_HOSTNAME: ${OPENBALENA_HOST_NAME}
volumes:
- certs:/certs:ro
cert-provider:
build: ../cert-provider
volumes:
- certs:/certs
- cert-provider:/usr/src/app/certs
environment:
ACTIVE: ${OPENBALENA_ACME_CERT_ENABLED}
DOMAINS: "api.${OPENBALENA_HOST_NAME},registry.${OPENBALENA_HOST_NAME},s3.${OPENBALENA_HOST_NAME},vpn.${OPENBALENA_HOST_NAME}"
OUTPUT_PEM: /certs/open-balena.pem

5
compose/versions Normal file
View File

@ -0,0 +1,5 @@
export OPENBALENA_API_VERSION_TAG=v0.11.8
export OPENBALENA_DB_VERSION_TAG=v2.0.3
export OPENBALENA_REGISTRY_VERSION_TAG=v2.5.0
export OPENBALENA_S3_VERSION_TAG=v2.6.2
export OPENBALENA_VPN_VERSION_TAG=v8.10.0

View File

@ -1,6 +1,10 @@
FROM haproxy:1.8-alpine
FROM haproxy:1.9-alpine
VOLUME [ "/certs" ]
RUN apk add --update inotify-tools
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
COPY entry.sh /open-balena-entry
COPY start-haproxy.sh /start-haproxy
CMD /open-balena-entry
CMD /start-haproxy

View File

@ -1,11 +0,0 @@
#!/bin/sh
set -e
HAPROXY_CHAIN=/etc/ssl/private/open-balena.pem
mkdir -p "$(dirname "${HAPROXY_CHAIN}")"
(
echo "${BALENA_HAPROXY_CRT}" | base64 -d
echo "${BALENA_HAPROXY_KEY}" | base64 -d
echo "${BALENA_ROOT_CA}" | base64 -d
) > "${HAPROXY_CHAIN}"
exec haproxy -f /usr/local/etc/haproxy/haproxy.cfg

View File

@ -12,6 +12,9 @@ frontend http-in
bind *:80
reqadd X-Forwarded-Proto:\ http
acl is_cert_validation path -i -m beg "/.well-known/acme-challenge/"
use_backend cert-provider if is_cert_validation
acl host_api hdr_dom(host) -i "api.${HAPROXY_HOSTNAME}"
use_backend backend_api if host_api
@ -80,6 +83,12 @@ backend backend_s3
option forwardfor
balance roundrobin
backend cert-provider
mode http
option forwardfor
balance roundrobin
server resin_cert-provider_1 cert-provider:80 no-check
backend vpn-devices
mode tcp
server resin_vpn_1 vpn:443 send-proxy-v2 check-send-proxy port 443

32
haproxy/start-haproxy.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
OPENBALENA_CERT=/etc/ssl/private/open-balena.pem
mkdir -p "$(dirname "${OPENBALENA_CERT}")"
if [ -f "/certs/open-balena.pem" ]; then
echo "Using certificate from cert-provider..."
cp /certs/open-balena.pem "${OPENBALENA_CERT}"
else
echo "Building certificate from environment variables..."
(
echo "${BALENA_HAPROXY_CRT}" | base64 -d
echo "${BALENA_HAPROXY_KEY}" | base64 -d
echo "${BALENA_ROOT_CA}" | base64 -d
) > "${OPENBALENA_CERT}"
fi
haproxy -f /usr/local/etc/haproxy/haproxy.cfg -W &
HAPROXY_PID=$!
while true; do
inotifywait -r -e create -e modify -e delete /certs
if [ -f "/certs/open-balena.pem" ]; then
echo "Updating certificate from cert-provider..."
cp /certs/open-balena.pem "${OPENBALENA_CERT}"
fi
echo "Certificate change detected. Reloading..."
kill -SIGUSR2 $HAPROXY_PID
sleep 1;
done

View File

@ -1,5 +1,11 @@
#!/bin/bash -e
echo_error() {
local RED=`tput setaf 1`
local RESET=`tput sgr0`
echo "${RED}ERROR: ${1}${RESET}"
}
REALPATH=
REALPATHS=(
'realpath'
@ -14,8 +20,13 @@ fi
done
if [ -z "${REALPATH}" ]; then
local RED=`tput setaf 1`
echo "${RED}ERROR: Unable to find suitable command for realpath."
echo_error 'Unable to find suitable command for realpath.'
if [ $(uname) == 'Darwin' ]; then
echo 'GNU coreutils are required to build openBalena on MacOS. To install with brew, run'
echo ''
echo ' brew install coreutils'
echo ''
fi
exit 1
fi

View File

@ -11,6 +11,12 @@ echo_bold() {
printf "\\033[1m%s\\033[0m\\n" "$@"
}
VERSIONS_FILE="${BASE_DIR}/compose/versions"
if [ ! -f "$VERSIONS_FILE" ]; then
echo_bold "No service versions defined in ${VERSIONS_FILE}"
exit 1
fi
ENV_FILE="${CONFIG_DIR}/activate"
if [ ! -f "$ENV_FILE" ]; then
echo_bold 'No configuration found; please create one first with: ./scripts/quickstart'
@ -19,7 +25,7 @@ if [ ! -f "$ENV_FILE" ]; then
fi
# shellcheck source=/dev/null
source "${ENV_FILE}"; docker-compose \
source "${VERSIONS_FILE}"; source "${ENV_FILE}"; docker-compose \
--project-name 'openbalena' \
-f "${BASE_DIR}/compose/services.yml" \
-f "${CONFIG_DIR}/docker-compose.yml" \

View File

@ -32,14 +32,9 @@ if [ ! -f $VPN_CA ] || [ ! -f $VPN_CRT ] || [ ! -f $VPN_KEY ] || [ ! -f $VPN_DH
rm -f $VPN_CA $VPN_CRT $VPN_DH $VPN_KEY
# generate VPN sub-CA
# generate VPN CA
"$easyrsa_bin" --pki-dir="${VPN_PKI}" init-pki &>/dev/null
"$easyrsa_bin" --pki-dir="${VPN_PKI}" --days="${CA_EXPIRY_DAYS}" --req-cn="vpn-ca.${CN}" build-ca nopass subca 2>/dev/null
# import sub-CA CSR into root PKI, sign, and copy back to vpn PKI
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" import-req "${VPN_PKI}/reqs/ca.req" "vpn-ca" 2>/dev/null
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" sign-req ca "vpn-ca" 2>/dev/null
cp "${ROOT_PKI}/issued/vpn-ca.crt" "${VPN_PKI}/ca.crt"
"$easyrsa_bin" --pki-dir="${VPN_PKI}" --days="${CA_EXPIRY_DAYS}" --req-cn="vpn-ca.${CN}" build-ca nopass 2>/dev/null
# generate and sign vpn server certificate
"$easyrsa_bin" --pki-dir="${VPN_PKI}" --days="${CRT_EXPIRY_DAYS}" build-server-full "vpn.${CN}" nopass 2>/dev/null
@ -48,8 +43,6 @@ if [ ! -f $VPN_CA ] || [ ! -f $VPN_CRT ] || [ ! -f $VPN_KEY ] || [ ! -f $VPN_DH
"$easyrsa_bin" --pki-dir="${VPN_PKI}" --keysize=2048 gen-dh 2>/dev/null
# update indexes and generate CRLs
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" update-db 2>/dev/null
"$easyrsa_bin" --pki-dir="${VPN_PKI}" update-db 2>/dev/null
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" gen-crl 2>/dev/null
"$easyrsa_bin" --pki-dir="${VPN_PKI}" gen-crl 2>/dev/null
fi

View File

@ -12,7 +12,7 @@ usage() {
echo " JWT_CRT Path to Token Auth certificate"
echo " JWT_KEY Path to Token Auth private key"
echo " JWT_KID Path to KeyID for the Token Auth certificate"
echo " VPN_CA Path to the VPN sub-CA certificate"
echo " VPN_CA Path to the VPN CA certificate"
echo " VPN_CRT Path to the VPN server certificate"
echo " VPN_KEY Path to the VPN server private key"
echo " VPN_DH Path to the VPN server Diffie Hellman parameters"
@ -83,7 +83,7 @@ export OPENBALENA_TOKEN_AUTH_PUB=$(b64file "$JWT_CRT")
export OPENBALENA_TOKEN_AUTH_KEY=$(b64file "$JWT_KEY")
export OPENBALENA_TOKEN_AUTH_KID=$(b64file "$JWT_KID")
export OPENBALENA_VPN_CA=$(b64file "$VPN_CA")
export OPENBALENA_VPN_CA_CHAIN=$(b64file "$ROOT_CA" "$VPN_CA")
export OPENBALENA_VPN_CA_CHAIN=$(b64file "$VPN_CA")
export OPENBALENA_VPN_CONFIG=$(b64encode "$VPN_CONFIG")
export OPENBALENA_VPN_SERVER_CRT=$(b64file "$VPN_CRT")
export OPENBALENA_VPN_SERVER_KEY=$(b64file "$VPN_KEY")
@ -94,4 +94,5 @@ export OPENBALENA_REGISTRY_SECRET_KEY=$(randstr 32)
export OPENBALENA_SSH_AUTHORIZED_KEYS=
export OPENBALENA_SUPERUSER_EMAIL=$SUPERUSER_EMAIL
export OPENBALENA_SUPERUSER_PASSWORD=$(printf "%q" "${SUPERUSER_PASSWORD}")
export OPENBALENA_ACME_CERT_ENABLED=${ACME_CERT_ENABLED:-false}
STR

View File

@ -21,6 +21,10 @@ fi
source "${BASH_SOURCE%/*}/_realpath"
domainResolves() {
getent hosts "$1" > /dev/null 2>&1
}
CMD="$(realpath "$0")"
DIR="$(dirname "${CMD}")"
BASE_DIR="$(dirname "${DIR}")"
@ -30,8 +34,9 @@ CERTS_DIR="${CONFIG_DIR}/certs"
DOMAIN=openbalena.local
usage() {
echo "usage: $0 [-h] [-p] [-d DOMAIN] -U EMAIL -P PASSWORD"
echo "usage: $0 [-c] [-h] [-p] [-d DOMAIN] -U EMAIL -P PASSWORD"
echo
echo " -c enable the ACME certificate service in staging or production mode."
echo " -p patch hosts - patch the host /etc/hosts file"
echo " -d DOMAIN the domain name this deployment will run as, eg. example.com. Default is 'openbalena.local'"
echo " -U EMAIL the email address of the superuser account, used to login to your install from the Balena CLI"
@ -41,7 +46,7 @@ usage() {
show_help=false
patch_hosts=false
while getopts ":hpxd:U:P:" opt; do
while getopts ":chpxd:U:P:" opt; do
case "${opt}" in
h) show_help=true;;
p) patch_hosts=true;;
@ -49,6 +54,7 @@ while getopts ":hpxd:U:P:" opt; do
d) DOMAIN="${OPTARG}";;
U) SUPERUSER_EMAIL="${OPTARG}";;
P) SUPERUSER_PASSWORD="${OPTARG}";;
c) ACME_CERT_ENABLED="true";;
*)
echo "Invalid argument: -${OPTARG}"
usage
@ -68,8 +74,17 @@ if [ "$show_help" = "true" ]; then
exit 1
fi
if [ ! -z "$ACME_CERT_ENABLED" ]; then
echo "${BLUE}[INFO]${RESET} ACME Certificate request is ${BOLD}ENABLED${RESET}."
if ! domainResolves "api.${DOMAIN}"; then
echo "${YELLOW}[WARN]${RESET} Unable to resolve \"api.${DOMAIN}\"!"
echo "${YELLOW}[WARN]${RESET} This might mean that you cannot use an ACME issued certificate."
fi
fi
echo_bold() {
printf "\\033[1m%s\\033[0m\\n" "${@}"
echo "${BOLD}${@}${RESET}"
}
echo_bold "==> Creating new configuration at: $CONFIG_DIR"
@ -110,5 +125,7 @@ fi
echo_bold "==> Success!"
echo ' - Start the instance with: ./scripts/compose up -d'
echo ' - Stop the instance with: ./scripts/compose stop'
echo ' - To create the superuser, see: ./scripts/create-superuser -h'
echo " - Use the following certificate with Balena CLI: ${CERTS_DIR}/root/ca.crt"
if [ -z "${ACME_CERT_ENABLED}" ]; then
echo " - Use the following certificate with Balena CLI: ${CERTS_DIR}/root/ca.crt"
fi