mirror of
https://github.com/balena-io/open-balena.git
synced 2025-06-24 10:18:15 +00:00
Compare commits
131 Commits
Author | SHA1 | Date | |
---|---|---|---|
dd59088cd2 | |||
cae93253a9 | |||
c4a18f5bf8 | |||
3b0c106eb1 | |||
c9fa4cf00f | |||
ea605d1444 | |||
966ea04241 | |||
dce59b65a3 | |||
f151d2a6cc | |||
4efb25afc7 | |||
08890adf92 | |||
44c11d9d16 | |||
e5bbfb833f | |||
a9107a1d6f | |||
f7207fb4a0 | |||
b39074c0ba | |||
3fed389090 | |||
96afd454bf | |||
0e0e5e1bc5 | |||
7c4e9fdc09 | |||
fbcb35a595 | |||
94f8b159c3 | |||
a328e8fc1d | |||
b1fd42669a | |||
39f7f6b0cc | |||
1180bb3462 | |||
fbf3007d4c | |||
2a3df9cd2a | |||
d71a90c1ef | |||
6739d1257b | |||
381fba943d | |||
66acae8bbf | |||
cd2c3f5e11 | |||
071b5850a9 | |||
91bc92dbb5 | |||
49831a6a60 | |||
549de52c73 | |||
826b61f08b | |||
0cdf0ef558 | |||
bea552de6a | |||
419f3cddc4 | |||
b92a3c8092 | |||
746be65846 | |||
6250c85551 | |||
3898342a5b | |||
ab0b7467fd | |||
7cdce1a1c7 | |||
da4c1678ec | |||
6fdc700806 | |||
e6d0be1c74 | |||
a0ef371621 | |||
cd98a0df3f | |||
296a746e96 | |||
b3d184c13c | |||
3b9433e9cc | |||
763da0eb45 | |||
bfce474ff0 | |||
308322f774 | |||
c2077e5037 | |||
7790290d0e | |||
857e6b3bd7 | |||
cbee20731b | |||
eec16b843d | |||
a3126359e0 | |||
6438da8498 | |||
1f7ed769c0 | |||
41b1800166 | |||
77e3cfcdb6 | |||
d3f11819ce | |||
3816f09bc4 | |||
7154c5903f | |||
71a692b28b | |||
feeb830405 | |||
eb262fe9a2 | |||
6db5e59958 | |||
d33560755f | |||
f427982714 | |||
b99e497ac9 | |||
de0293563f | |||
17419557a5 | |||
c58ee37f17 | |||
d67e29223f | |||
08a990d32d | |||
d70c2177ff | |||
2a7d0687a2 | |||
e6c865e383 | |||
617209dc9e | |||
853ffb33e8 | |||
a029160caf | |||
bb1328e27e | |||
395613af57 | |||
199d8eb4a4 | |||
6fdc554e43 | |||
f8b8a1589a | |||
3bf14a2140 | |||
fef145f993 | |||
e068f8058f | |||
c1ee146f0d | |||
9ad92596b9 | |||
56de2d20bb | |||
290c90c262 | |||
98b6100fed | |||
e1bfb7f7b0 | |||
35ab5300e6 | |||
fd031ad3a4 | |||
95d53993bc | |||
1721728794 | |||
061440f109 | |||
2f0fb27145 | |||
210bdcda37 | |||
fac66040c8 | |||
85a69c1ef1 | |||
e37a61e5f0 | |||
0fc85ff5b6 | |||
99dd615e55 | |||
d3b021a1cb | |||
b9b9b65ce6 | |||
9fb3f76858 | |||
52fb653223 | |||
7332b6971e | |||
011f3a35f9 | |||
0842b7b4ae | |||
37ecfb8996 | |||
bd638ac409 | |||
cec371f0b8 | |||
eb1db83058 | |||
709d00b898 | |||
6f56ee8fbd | |||
9d48debca6 | |||
254fd3b499 | |||
5bc74c3f75 |
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,5 +1,11 @@
|
||||
.DS_Store
|
||||
.project
|
||||
.vagrant/
|
||||
config/
|
||||
src/
|
||||
|
||||
meta.json
|
||||
landr-dist
|
||||
*.traineddata
|
||||
|
||||
/config
|
||||
/docker-compose.yml
|
||||
/package-lock.json
|
||||
|
50
.openbalenarc
Normal file
50
.openbalenarc
Normal file
@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
alias dc="/home/vagrant/openbalena/scripts/compose"
|
||||
|
||||
function enter () {
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: enter <service name> [command]"
|
||||
echo " "
|
||||
echo " Runs a [command] in the service specified."
|
||||
echo " "
|
||||
echo " command:"
|
||||
echo " (default) /bin/bash"
|
||||
echo " "
|
||||
echo " example:"
|
||||
echo " enter api # this will run the command '/bin/bash' in the API service, providing a shell prompt"
|
||||
echo " enter api uptime # this will run the command 'uptime' in the API service, and return"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
service="$1"
|
||||
shift
|
||||
COMMAND=/bin/bash
|
||||
if [[ $# -gt 0 ]]; then
|
||||
COMMAND="$@"
|
||||
fi
|
||||
dc exec ${service} /bin/bash -c "${COMMAND}"
|
||||
}
|
||||
|
||||
function logs () {
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: logs <service name> [options]"
|
||||
echo " "
|
||||
echo " Shows the logs from journalctl in the service specified."
|
||||
echo " "
|
||||
echo " options:"
|
||||
echo " -f tail the log stream"
|
||||
echo " -n number of lines to take"
|
||||
echo " "
|
||||
echo " example:"
|
||||
echo " logs api -fn100 # this will tail the API log, starting with the last 100 lines"
|
||||
return 1
|
||||
fi
|
||||
|
||||
service="$1"
|
||||
shift
|
||||
enter ${service} journalctl "$@"
|
||||
}
|
||||
|
||||
cd /home/vagrant/openbalena
|
5337
.versionbot/CHANGELOG.yml
Normal file
5337
.versionbot/CHANGELOG.yml
Normal file
File diff suppressed because it is too large
Load Diff
2530
CHANGELOG.md
2530
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
30
CONTRIBUTING.md
Normal file
30
CONTRIBUTING.md
Normal file
@ -0,0 +1,30 @@
|
||||
# Contributing to openbalena
|
||||
|
||||
Everyone is welcome to contribute to openBalena. There are many different ways
|
||||
to get involved apart from submitting pull requests, including helping other
|
||||
users on the [forums][forums], reporting or triaging [issues][issue-tracker],
|
||||
reviewing and discussing [pull requests][pulls], or just spreading the word.
|
||||
|
||||
All of openbalena is hosted on GitHub. Apart from its constituent components,
|
||||
which are the [API][open-balena-api], [VPN][open-balena-vpn], [Registry][open-balena-registry],
|
||||
[S3 storage service][open-balena-s3], and [Database][open-balena-db], contributions
|
||||
are also welcome to its client-side software such as the [balena CLI][balena-cli],
|
||||
the [balena SDK][balena-sdk], [balenaOS][balena-os] and [balenaEngine][balena-engine].
|
||||
|
||||
[balena-cli]: https://github.com/balena-io/balena-cli
|
||||
[balena-cloud-website]: https://balena.io/cloud
|
||||
[balena-engine]: https://github.com/balena-os/balena-engine
|
||||
[balena-os-website]: https://balena.io/os
|
||||
[balena-os]: https://github.com/balena-os/meta-balena
|
||||
[balena-sdk]: https://github.com/balena-io/balena-sdk
|
||||
[documentation]: https://balena.io/docs/learn/welcome/introduction/
|
||||
[forums]: https://forums.balena.io/c/open-balena
|
||||
[getting-started]: https://balena.io/open/docs/getting-started
|
||||
[issue-tracker]: https://github.com/balena-io/open-balena/issues
|
||||
[open-balena-api]: https://github.com/balena-io/open-balena-api
|
||||
[open-balena-db]: https://github.com/balena-io/open-balena-db
|
||||
[open-balena-registry]: https://github.com/balena-io/open-balena-registry
|
||||
[open-balena-s3]: https://github.com/balena-io/open-balena-s3
|
||||
[open-balena-vpn]: https://github.com/balena-io/open-balena-vpn
|
||||
[open-balena-website]: https://balena.io/open
|
||||
[pulls]: https://github.com/balena-io/open-balena/pulls
|
77
README.md
77
README.md
@ -1,22 +1,8 @@
|
||||
<img alt="openBalena" src="docs/assets/openbalena-logo.svg" height="82">
|
||||

|
||||
|
||||
---
|
||||
|
||||
OpenBalena is a platform to deploy and manage connected devices. Devices run
|
||||
[balenaOS][balena-os-website], a host operating system designed for running
|
||||
containers on IoT devices, and are managed via the [balena CLI][balena-cli],
|
||||
which you can use to configure your application containers, push updates, check
|
||||
status, view logs, and so forth. OpenBalena’s backend services, composed of
|
||||
battle-tested components that we’ve run in production on [balenaCloud][balena-cloud-website]
|
||||
for years, can store device information securely and reliably, allow remote
|
||||
management via a built-in VPN service, and efficiently distribute container
|
||||
images to your devices.
|
||||
|
||||
To learn more about openBalena, visit [balena.io/open][open-balena-website].
|
||||
|
||||
|
||||
## Features
|
||||
**openbalena is an open source platform to manage IoT and edge device fleets at scale.**
|
||||
|
||||
## Highlights
|
||||
- **Simple provisioning**: Adding devices to your fleet is a breeze
|
||||
- **Easy updates**: Remotely update the software on your devices with a single command
|
||||
- **Container-based**: Benefit from the power of virtualization, optimized for the edge
|
||||
@ -24,44 +10,30 @@ To learn more about openBalena, visit [balena.io/open][open-balena-website].
|
||||
- **Powerful API & SDK**: Extend openBalena to fit your needs
|
||||
- **Built-in VPN**: Access your devices regardless of their network environment
|
||||
|
||||
## Motivation
|
||||
|
||||
## Roadmap
|
||||
openbalena is a platform that helps you deploy and manage connected devices. Devices run [balenaOS][balena-os-website], a host operating system designed for running containers on IoT devices, and are managed via the [balena CLI][balena-cli], which you can use to configure your application containers, push updates, check status, view logs, and more.
|
||||
|
||||
OpenBalena is currently in beta. While fully functional, it lacks features we
|
||||
consider important before we can comfortably call it production-ready. During
|
||||
this phase, don’t be alarmed if things don’t work as expected just yet (and
|
||||
please let us know about any bugs or errors you encounter!). The following
|
||||
improvements and new functionality is planned:
|
||||
openbalena’s backend services, composed of battle-tested components that we’ve run in production on [balenaCloud][balena-cloud-website] for years, can store device information securely and reliably, allow remote management via a built-in VPN service, and efficiently distribute container images to your devices.
|
||||
|
||||
- Full documentation
|
||||
- Full test suite
|
||||
- Simplified deployment
|
||||
- Remote host OS updates
|
||||
- Support for custom device types
|
||||
To learn more about openbalena, visit [balena.io/open][open-balena-website].
|
||||
|
||||
### Setup and Configuration
|
||||
|
||||
## Contributing
|
||||
Our [Getting Started guide][getting-started] is the most direct path to getting an openbalena installation up and running and successfully deploying your application to your device(s).
|
||||
|
||||
Everyone is welcome to contribute to openBalena. There are many different ways
|
||||
to get involved apart from submitting pull requests, including helping other
|
||||
users on the [forums][forums], reporting or triaging [issues][issue-tracker],
|
||||
reviewing and discussing [pull requests][pulls], or just spreading the word.
|
||||
### Compatibility
|
||||
|
||||
All of openBalena is hosted on GitHub. Apart from its constituent components,
|
||||
which are the [API][open-balena-api], [VPN][open-balena-vpn], [Registry][open-balena-registry],
|
||||
[S3 storage service][open-balena-s3], and [Database][open-balena-db], contributions
|
||||
are also welcome to its client-side software such as the [balena CLI][balena-cli],
|
||||
the [balena SDK][balena-sdk], [balenaOS][balena-os] and [balenaEngine][balena-engine].
|
||||
The current release of openBalena has the following minimum version requirements:
|
||||
|
||||
- balenaOS v2.58.3
|
||||
- balena CLI v12.38.5
|
||||
|
||||
## Getting Started
|
||||
If you are updating from previous openBalena versions, ensure you update the balena
|
||||
CLI and reprovision any devices to at least the minimum required versions in order
|
||||
for them to be fully compatible with this release, as some features may not work.
|
||||
|
||||
Our [Getting Started][getting-started] guide is the most direct path to getting
|
||||
an openBalena installation up and running and successfully deploying your
|
||||
application to your device(s).
|
||||
|
||||
|
||||
## Documentation
|
||||
### Documentation
|
||||
|
||||
While we're still working on the project documentation, please refer to the
|
||||
[balenaCloud documentation][documentation]. BalenaCloud is built on top of
|
||||
@ -79,20 +51,9 @@ sections are of particular interest:
|
||||
- [Reference](https://balena.io/docs/reference)
|
||||
- [FAQ](https://balena.io/docs/faq/troubleshooting/faq)
|
||||
|
||||
### License
|
||||
|
||||
## Getting Help
|
||||
|
||||
You are welcome to submit any questions, participate in discussions and request
|
||||
help with any issue in [openBalena forums][forums]. The balena team frequents
|
||||
these forums and will be happy to help. You can also ask other community members
|
||||
for help, or contribute by answering questions posted by fellow openBalena users.
|
||||
Please do not use the issue tracker for support-related questions.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
OpenBalena is licensed under the terms of AGPL v3. See [LICENSE](LICENSE) for details.
|
||||
|
||||
openbalena is licensed under the terms of AGPL v3. See [LICENSE](LICENSE) for details.
|
||||
|
||||
[balena-cli]: https://github.com/balena-io/balena-cli
|
||||
[balena-cloud-website]: https://balena.io/cloud
|
||||
|
48
Vagrantfile
vendored
48
Vagrantfile
vendored
@ -1,31 +1,41 @@
|
||||
Vagrant.require_version '>= 2.0.0'
|
||||
|
||||
[ 'vagrant-vbguest', 'vagrant-docker-compose' ].each do |p|
|
||||
unless Vagrant.has_plugin?(p)
|
||||
raise "Please install missing plugin: vagrant plugin install #{p}"
|
||||
end
|
||||
end
|
||||
Vagrant.require_version '>= 2.2.0'
|
||||
|
||||
Vagrant.configure('2') do |config|
|
||||
config.vm.define 'openbalenavm'
|
||||
config.vm.box = 'bento/ubuntu-16.04'
|
||||
config.vm.box_url = 'https://vagrantcloud.com/bento/boxes/ubuntu-16.04/versions/201808.24.0/providers/virtualbox.box'
|
||||
config.vagrant.plugins = [
|
||||
'vagrant-vbguest',
|
||||
'vagrant-docker-compose'
|
||||
]
|
||||
|
||||
config.vm.define 'openbalena'
|
||||
config.vm.hostname = 'openbalena-vagrant'
|
||||
config.vm.box = 'bento/ubuntu-18.04'
|
||||
|
||||
config.vm.network "public_network",
|
||||
use_dhcp_assigned_default_route: true
|
||||
|
||||
config.vm.synced_folder '.', '/vagrant', disabled: true
|
||||
config.vm.synced_folder '.', '/home/vagrant/open-balena'
|
||||
config.vm.network 'public_network', bridge: ENV.fetch('OPENBALENA_BRIDGE', '')
|
||||
config.vm.synced_folder '.', '/home/vagrant/openbalena'
|
||||
|
||||
config.ssh.forward_agent = true
|
||||
|
||||
config.vm.provision :docker
|
||||
config.vm.provision :docker_compose
|
||||
|
||||
# FIXME: remove node
|
||||
config.vm.provision :shell, inline: 'apt-get update && apt-get install -y nodejs && rm -rf /var/lib/apt/lists/*'
|
||||
$provision = <<-SCRIPT
|
||||
DOCKER_COMPOSE_VERSION=1.24.0
|
||||
|
||||
config.vm.provision :shell, privileged: false,
|
||||
inline: "cd /home/vagrant/open-balena && ./scripts/quickstart -p -d #{ENV.fetch('OPENBALENA_DOMAIN', 'openbalena.local')}"
|
||||
touch /home/vagrant/.bashrc
|
||||
grep -Fxq 'source /home/vagrant/openbalena/.openbalenarc' /home/vagrant/.bashrc || echo 'source /home/vagrant/openbalena/.openbalenarc' >> /home/vagrant/.bashrc
|
||||
|
||||
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
|
||||
source "/home/vagrant/.nvm/nvm.sh" # This loads nvm
|
||||
nvm install 10.15.0 && nvm use 10.15.0
|
||||
|
||||
# Install a newer version of docker-compose
|
||||
(cd /usr/local/bin; \
|
||||
sudo curl -o docker-compose --silent --location https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-Linux-x86_64; \
|
||||
sudo chmod a+x docker-compose)
|
||||
SCRIPT
|
||||
|
||||
config.vm.provision :shell, privileged: false, inline: $provision
|
||||
|
||||
config.vm.provision :shell, privileged: false,
|
||||
inline: "echo 'cd ~/open-balena' >> ~/.bashrc"
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: '2.1'
|
||||
version: "2.0"
|
||||
|
||||
services:
|
||||
component:
|
||||
|
31
compose/mdns.yml
Normal file
31
compose/mdns.yml
Normal file
@ -0,0 +1,31 @@
|
||||
version: "2.0"
|
||||
|
||||
services:
|
||||
balena-mdns-publisher:
|
||||
image: balena/balena-mdns-publisher:${OPENBALENA_MDNS_PUBLISHER_VERSION_TAG}
|
||||
network_mode: "host"
|
||||
cap_add:
|
||||
- SYS_RESOURCE
|
||||
- SYS_ADMIN
|
||||
security_opt:
|
||||
- apparmor:unconfined
|
||||
tmpfs:
|
||||
- /run
|
||||
- /sys/fs/cgroup
|
||||
# balenaOS - Required for host DBus comms. Not required for standalone Linux
|
||||
labels:
|
||||
io.balena.features.dbus: '1'
|
||||
io.balena.features.supervisor-api: '1'
|
||||
environment:
|
||||
CONFD_BACKEND: ENV
|
||||
# The name of the TLD to use. This *must* match certificates used for the rest of
|
||||
# the resin backend (eg. that for BALENA_ROOT_CA if present).
|
||||
MDNS_TLD: ${OPENBALENA_HOST_NAME}
|
||||
# List of subdomains to advertise. This must include all required hosts.
|
||||
MDNS_SUBDOMAINS: '["api", "db", "registry", "s3", "tunnel", "vpn"]'
|
||||
# The expectation is the DBus socket to use is always at the following location.
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/host/run/dbus/system_bus_socket"
|
||||
# Selects the interface used for incoming connections from the wider subnet.
|
||||
# For NUCs, this is `eno1`. If running natively, pick the appropriate interface.
|
||||
# Alternatively, keep the default commented out to autoselect.
|
||||
#INTERFACE: "eno1"
|
@ -1,17 +1,18 @@
|
||||
version: '2.1'
|
||||
version: "2.0"
|
||||
|
||||
volumes:
|
||||
db:
|
||||
registry:
|
||||
s3:
|
||||
redis:
|
||||
certs: {}
|
||||
cert-provider: {}
|
||||
db: {}
|
||||
redis: {}
|
||||
s3: {}
|
||||
|
||||
services:
|
||||
api:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: balena/open-balena-api:${OPENBALENA_API_VERSION_TAG:-master}
|
||||
image: balena/open-balena-api:${OPENBALENA_API_VERSION_TAG}
|
||||
depends_on:
|
||||
- db
|
||||
- s3
|
||||
@ -20,36 +21,35 @@ 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
|
||||
DELTA_HOST: delta.${OPENBALENA_HOST_NAME}
|
||||
DEVICE_CONFIG_OPENVPN_CONFIG: ${OPENBALENA_VPN_CONFIG}
|
||||
DEVICE_CONFIG_OPENVPN_CA: ${OPENBALENA_VPN_CA_CHAIN}
|
||||
DEVICE_CONFIG_SSH_AUTHORIZED_KEYS: ${OPENBALENA_SSH_AUTHORIZED_KEYS}
|
||||
HOST: api.${OPENBALENA_HOST_NAME}
|
||||
IMAGE_MAKER_URL: img.${OPENBALENA_HOST_NAME}
|
||||
IMAGE_STORAGE_BUCKET: resin-production-img-cloudformation
|
||||
IMAGE_STORAGE_PREFIX: resinos
|
||||
IMAGE_STORAGE_PREFIX: images
|
||||
IMAGE_STORAGE_ENDPOINT: s3.amazonaws.com
|
||||
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}
|
||||
SENTRY_DSN:
|
||||
SENTRY_DSN: ""
|
||||
TOKEN_AUTH_BUILDER_TOKEN: ${OPENBALENA_TOKEN_AUTH_BUILDER_TOKEN}
|
||||
TOKEN_AUTH_CERT_ISSUER: api.${OPENBALENA_HOST_NAME}
|
||||
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}
|
||||
@ -60,31 +60,35 @@ services:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: balena/open-balena-registry:${OPENBALENA_REGISTRY_VERSION_TAG:-master}
|
||||
image: balena/open-balena-registry:${OPENBALENA_REGISTRY_VERSION_TAG}
|
||||
depends_on:
|
||||
- api
|
||||
- s3
|
||||
- redis
|
||||
volumes:
|
||||
- registry:/data
|
||||
environment:
|
||||
API_TOKENAUTH_CRT: ${OPENBALENA_TOKEN_AUTH_PUB}
|
||||
BALENA_REGISTRY2_HOST: registry.${OPENBALENA_HOST_NAME}
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
BALENA_TOKEN_AUTH_ISSUER: api.${OPENBALENA_HOST_NAME}
|
||||
BALENA_TOKEN_AUTH_REALM: https://api.${OPENBALENA_HOST_NAME}/auth/v1/token
|
||||
COMMON_REGION:
|
||||
REGISTRY2_S3_BUCKET:
|
||||
REGISTRY2_S3_KEY:
|
||||
REGISTRY2_S3_SECRET:
|
||||
COMMON_REGION: ${OPENBALENA_S3_REGION}
|
||||
REGISTRY2_CACHE_ENABLED: "false"
|
||||
REGISTRY2_CACHE_ADDR: 127.0.0.1:6379
|
||||
REGISTRY2_CACHE_DB: 0
|
||||
REGISTRY2_CACHE_MAXMEMORY_MB: 1024 # megabytes
|
||||
REGISTRY2_CACHE_MAXMEMORY_POLICY: allkeys-lru
|
||||
REGISTRY2_S3_REGION_ENDPOINT: ${OPENBALENA_S3_ENDPOINT}
|
||||
REGISTRY2_S3_BUCKET: ${OPENBALENA_REGISTRY2_S3_BUCKET}
|
||||
REGISTRY2_S3_KEY: ${OPENBALENA_S3_ACCESS_KEY}
|
||||
REGISTRY2_S3_SECRET: ${OPENBALENA_S3_SECRET_KEY}
|
||||
REGISTRY2_SECRETKEY: ${OPENBALENA_REGISTRY_SECRET_KEY}
|
||||
REGISTRY2_STORAGEPATH: /data
|
||||
REGISTRY2_DISABLE_REDIRECT: "false"
|
||||
|
||||
vpn:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: balena/open-balena-vpn:${OPENBALENA_VPN_VERSION_TAG:-master}
|
||||
image: balena/open-balena-vpn:${OPENBALENA_VPN_VERSION_TAG}
|
||||
depends_on:
|
||||
- api
|
||||
cap_add:
|
||||
@ -94,10 +98,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'
|
||||
SENTRY_DSN: ""
|
||||
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}
|
||||
@ -108,17 +112,21 @@ services:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: system
|
||||
image: balena/open-balena-db:${OPENBALENA_DB_VERSION_TAG:-master}
|
||||
image: balena/open-balena-db:${OPENBALENA_DB_VERSION_TAG}
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
|
||||
s3:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: system
|
||||
image: balena/open-balena-s3:${OPENBALENA_S3_VERSION_TAG:-master}
|
||||
service: component
|
||||
image: balena/open-balena-s3:${OPENBALENA_S3_VERSION_TAG}
|
||||
volumes:
|
||||
- s3:/export
|
||||
environment:
|
||||
S3_MINIO_ACCESS_KEY: ${OPENBALENA_S3_ACCESS_KEY}
|
||||
S3_MINIO_SECRET_KEY: ${OPENBALENA_S3_SECRET_KEY}
|
||||
BUCKETS: ${OPENBALENA_S3_BUCKETS}
|
||||
|
||||
redis:
|
||||
extends:
|
||||
@ -132,21 +140,23 @@ services:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: system
|
||||
build: ../haproxy
|
||||
build: ../src/haproxy
|
||||
depends_on:
|
||||
- api
|
||||
- registry
|
||||
- vpn
|
||||
- cert-provider
|
||||
- db
|
||||
- s3
|
||||
- redis
|
||||
- registry
|
||||
- vpn
|
||||
ports:
|
||||
- "80:80"
|
||||
- "222:222"
|
||||
- "443:443"
|
||||
- "3128:3128"
|
||||
- "5432:5432"
|
||||
- "6379:6379"
|
||||
expose:
|
||||
- "222"
|
||||
- "3128"
|
||||
- "5432"
|
||||
- "6379"
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
@ -156,8 +166,21 @@ services:
|
||||
- db.${OPENBALENA_HOST_NAME}
|
||||
- s3.${OPENBALENA_HOST_NAME}
|
||||
- redis.${OPENBALENA_HOST_NAME}
|
||||
- tunnel.${OPENBALENA_HOST_NAME}
|
||||
environment:
|
||||
BALENA_HAPROXY_CRT: ${OPENBALENA_ROOT_CRT}
|
||||
BALENA_HAPROXY_KEY: ${OPENBALENA_ROOT_KEY}
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
HAPROXY_HOSTNAME: ${OPENBALENA_HOST_NAME}
|
||||
volumes:
|
||||
- certs:/certs:ro
|
||||
|
||||
cert-provider:
|
||||
build: ../src/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},tunnel.${OPENBALENA_HOST_NAME}"
|
||||
OUTPUT_PEM: /certs/open-balena.pem
|
||||
|
@ -7,4 +7,4 @@
|
||||
# `compose/services.yml` as the "base" config.
|
||||
#
|
||||
# You may view the effective config with `scripts/compose config`.
|
||||
version: '2.1'
|
||||
version: "2.0"
|
||||
|
6
compose/versions
Normal file
6
compose/versions
Normal file
@ -0,0 +1,6 @@
|
||||
export OPENBALENA_API_VERSION_TAG=v0.139.0
|
||||
export OPENBALENA_DB_VERSION_TAG=v4.1.0
|
||||
export OPENBALENA_MDNS_PUBLISHER_VERSION_TAG=v1.9.2
|
||||
export OPENBALENA_REGISTRY_VERSION_TAG=v2.16.1
|
||||
export OPENBALENA_S3_VERSION_TAG=v2.9.9
|
||||
export OPENBALENA_VPN_VERSION_TAG=v9.17.11
|
226
docs/01-getting-started.md
Normal file
226
docs/01-getting-started.md
Normal file
@ -0,0 +1,226 @@
|
||||
# Getting started with openbalena
|
||||
|
||||
This guide will walk you through the steps of deploying an openBalena server,
|
||||
that together with the balena CLI, will enable you to create and manage a fleet
|
||||
of devices running on your own infrastructure, on premises or in the cloud. The
|
||||
openBalena servers must be reachable by the devices, which is easiest to achieve
|
||||
with cloud providers like AWS, Google Cloud, Digital Ocean and others.
|
||||
|
||||
This guide assumes a setup with two separate machines:
|
||||
|
||||
- The openBalena _server_, running Linux. These instructions were tested with an
|
||||
Ubuntu 18.04 x64 server.
|
||||
- The _local machine_, running Linux, Windows or macOS where the balena CLI runs
|
||||
(as a client to the openBalena server). The local machine should also have a
|
||||
working installation of [Docker](https://docs.docker.com/get-docker/) so that
|
||||
application images can be built and deployed to your devices, although it is
|
||||
also possible to use balenaEngine on a balenaOS device instead of Docker.
|
||||
|
||||
## Preparing a server for openBalena
|
||||
|
||||
Login to the server via SSH and run the following commands.
|
||||
|
||||
1. First, install or update essential software:
|
||||
|
||||
```bash
|
||||
apt-get update && apt-get install -y build-essential git docker.io libssl-dev nodejs npm
|
||||
```
|
||||
|
||||
2. Install docker-compose:
|
||||
|
||||
```bash
|
||||
curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-Linux-x86_64 -o /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
Test your docker-compose installation with `$ docker-compose --version`.
|
||||
|
||||
3. Create a new user, assign admin permissions and add to `docker` group:
|
||||
|
||||
```bash
|
||||
adduser balena
|
||||
usermod -aG sudo balena
|
||||
usermod -aG docker balena
|
||||
```
|
||||
|
||||
### Install openBalena on the server
|
||||
|
||||
1. On the server still, login as the new user and change into the home directory:
|
||||
|
||||
```bash
|
||||
su balena
|
||||
cd ~
|
||||
```
|
||||
|
||||
2. Clone the openBalena repository and change into the new directory:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/balena-io/open-balena.git
|
||||
cd open-balena/
|
||||
```
|
||||
|
||||
3. Run the `quickstart` script as below. This will create a new `config`
|
||||
directory and generate appropriate SSL certificates and configuration for the
|
||||
server. The provided email and password will be used to automatically create
|
||||
the user account for interacting with the server and will be needed later on
|
||||
for logging in via the balena CLI. Replace the domain name for the `-d`
|
||||
argument appropriately.
|
||||
|
||||
```bash
|
||||
./scripts/quickstart -U <email@address> -P <password> -d mydomain.com
|
||||
```
|
||||
|
||||
For more available options, see the script's help:
|
||||
|
||||
```bash
|
||||
./scripts/quickstart -h
|
||||
```
|
||||
|
||||
4. At this point, the openBalena server can be started with:
|
||||
|
||||
```bash
|
||||
systemctl start docker
|
||||
./scripts/compose up -d
|
||||
```
|
||||
|
||||
The `-d` argument spawns the containers as background services.
|
||||
|
||||
5. Tail the logs of the containers with:
|
||||
|
||||
```bash
|
||||
./scripts/compose exec <service-name> journalctl -fn100
|
||||
```
|
||||
|
||||
Replace `<service-name>` with the name of any one of the services defined
|
||||
in `compose/services.yml`; eg. `api` or `registry`.
|
||||
|
||||
6. The server can be stopped with:
|
||||
|
||||
```bash
|
||||
./scripts/compose stop
|
||||
```
|
||||
|
||||
When updating openBalena to a new version, the steps are:
|
||||
|
||||
```bash
|
||||
./scripts/compose down
|
||||
git pull
|
||||
./scripts/compose build
|
||||
./scripts/compose up -d
|
||||
```
|
||||
|
||||
### Domain Configuration
|
||||
|
||||
The following CNAME records must be configured to point to the openBalena server:
|
||||
|
||||
```text
|
||||
api.mydomain.com
|
||||
registry.mydomain.com
|
||||
vpn.mydomain.com
|
||||
s3.mydomain.com
|
||||
tunnel.mydomain.com
|
||||
```
|
||||
|
||||
Check with your internet domain name registrar for instructions on how to
|
||||
configure CNAME records.
|
||||
|
||||
### Test the openBalena server
|
||||
|
||||
To confirm that everything is running correctly, try a simple request from the
|
||||
local machine to the server:
|
||||
|
||||
```bash
|
||||
curl -k https://api.mydomain.com/ping
|
||||
OK
|
||||
```
|
||||
|
||||
Congratulations! The openBalena server is up and running. The next step is to
|
||||
setup the local machine to use the server, provision a device and deploy a
|
||||
small project.
|
||||
|
||||
## Install self-signed certificates on the local machine
|
||||
|
||||
The installation of the openBalena server produces a few self-signed certificates
|
||||
that must be installed on the local machine, so that it can securely communicate
|
||||
with the server.
|
||||
|
||||
The root certificate is found at `config/certs/root/ca.crt` on the server. Copy
|
||||
it to some folder on the local machine and keep a note the path -- it will be
|
||||
used later during the CLI installation. Follow the steps below for the specific
|
||||
platform of the local machine.
|
||||
|
||||
### Linux:
|
||||
|
||||
```bash
|
||||
sudo cp ca.crt /usr/local/share/ca-certificates/ca.crt
|
||||
sudo update-ca-certificates
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
### macOS:
|
||||
|
||||
```bash
|
||||
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.crt
|
||||
osascript -e 'quit app "Docker"' && open -a Docker
|
||||
```
|
||||
|
||||
### Windows:
|
||||
|
||||
```bash
|
||||
certutil -addstore -f "ROOT" ca.crt
|
||||
```
|
||||
|
||||
The Docker daemon on the local machine must then be restarted for Docker to
|
||||
pick up the new certificate.
|
||||
|
||||
## Install the balena CLI on the local machine
|
||||
|
||||
Follow the [balena CLI installation
|
||||
instructions](https://github.com/balena-io/balena-cli/blob/master/INSTALL.md)
|
||||
to install the balena CLI on the local machine.
|
||||
|
||||
By default, the CLI targets the balenaCloud servers at `balena-cloud.com`, and
|
||||
needs to be configured to target the openBalena server instead. Add the following
|
||||
line to the CLI's configuration file, replacing `"mydomain.com"` with the domain
|
||||
name of the openBalena server:
|
||||
|
||||
```yaml
|
||||
balenaUrl: 'mydomain.com'
|
||||
```
|
||||
|
||||
The CLI configuration file can be found at:
|
||||
|
||||
- On Linux or macOS: `~/.balenarc.yml`
|
||||
- On Windows: `%UserProfile%\_balenarc.yml`
|
||||
|
||||
If the file does not already exist, just create it.
|
||||
|
||||
Wrapping up the CLI installation, set an environment variable that points to the
|
||||
root certificate copied previously on the local machine. This step is to ensure
|
||||
the CLI can securely interact with the openBalena server.
|
||||
|
||||
| Shell | Command |
|
||||
| ------------------ | ---------------------------------------------- |
|
||||
| bash | `export NODE_EXTRA_CA_CERTS='/path/to/ca.crt'` |
|
||||
| Windows cmd.exe | `set NODE_EXTRA_CA_CERTS=C:\path\to\ca.crt` |
|
||||
| Windows PowerShell | `$Env:NODE_EXTRA_CA_CERTS="C:\path\to\ca.crt"` |
|
||||
|
||||
## Deploy an application
|
||||
|
||||
The commands below should be run on a terminal on the local machine (where the
|
||||
balena CLI is installed). Ensure that the `NODE_EXTRA_CA_CERTS` environment
|
||||
variable is set, as discussed above.
|
||||
|
||||
### Login to openBalena
|
||||
|
||||
Run `balena login`, select `Credentials` and use the email and password
|
||||
specified during quickstart to login to the openBalena server. At any time, the
|
||||
`balena whoami` command may be used to check which server the CLI is logged in to.
|
||||
|
||||
## Getting Help
|
||||
|
||||
You are welcome to submit any questions, participate in discussions and request
|
||||
help with any issue in [openBalena forums][forums]. The balena team frequents
|
||||
these forums and will be happy to help. You can also ask other community members
|
||||
for help, or contribute by answering questions posted by fellow openBalena users.
|
||||
Please do not use the issue tracker for support-related questions.
|
143
docs/02-deploy-an-application-or-fleet.md
Normal file
143
docs/02-deploy-an-application-or-fleet.md
Normal file
@ -0,0 +1,143 @@
|
||||
# Deploy and provision an application
|
||||
|
||||
The commands below should be run on a terminal on the local machine (where the
|
||||
balena CLI is installed). Ensure that the `NODE_EXTRA_CA_CERTS` environment
|
||||
variable is set, as discussed above.
|
||||
|
||||
### Login to openBalena
|
||||
|
||||
Run `balena login`, select `Credentials` and use the email and password
|
||||
specified during quickstart to login to the openBalena server. At any time, the
|
||||
`balena whoami` command may be used to check which server the CLI is logged in to.
|
||||
|
||||
### Create an application
|
||||
|
||||
Create a new application with `balena app create myApp`. Select the application's
|
||||
default device type with the interactive prompt. The examples in this guide assume
|
||||
a Raspberry Pi 3.
|
||||
|
||||
An application contains devices that share the same architecture (such as ARM
|
||||
or Intel i386), and also contains code releases that are deployed to the devices.
|
||||
When a device is provisioned, it is added to an application, but can be migrated
|
||||
to another application at any time. There is no limit to the number of applications
|
||||
that can be created or to the number of devices that can be provisioned.
|
||||
|
||||
At any time, the server can be queried for all the applications it knows about
|
||||
with the following command:
|
||||
|
||||
```bash
|
||||
balena apps
|
||||
ID APP NAME DEVICE TYPE ONLINE DEVICES DEVICE COUNT
|
||||
1 myApp raspberrypi3
|
||||
```
|
||||
|
||||
### Provision a new device
|
||||
|
||||
Once we have an application, it’s time to start provisioning devices. To do this,
|
||||
first download a balenaOS image from [balena.io](https://balena.io/os/#download).
|
||||
Pick the development image that is appropriate for your device.
|
||||
|
||||
Unzip the downloaded image and use the balena CLI to configure it:
|
||||
|
||||
```bash
|
||||
balena os configure ~/Downloads/balena-cloud-raspberrypi3-2.58.3+rev1-dev-v11.14.0.img --app myApp
|
||||
```
|
||||
|
||||
Flash the configured image to an SD card using [Etcher](https://balena.io/etcher).
|
||||
Insert the SD card into the device and power it on. The device will register with
|
||||
the openBalena server and after about two minutes will be inspectable:
|
||||
|
||||
```bash
|
||||
balena devices
|
||||
ID UUID DEVICE NAME DEVICE TYPE APPLICATION NAME STATUS IS ONLINE SUPERVISOR VERSION OS VERSION
|
||||
4 59d7700 winter-tree raspberrypi3 myApp Idle true 11.14.0 balenaOS 2.58.3+rev1
|
||||
|
||||
balena device 59d7700
|
||||
== WINTER TREE
|
||||
ID: 4
|
||||
DEVICE TYPE: raspberrypi3
|
||||
STATUS: online
|
||||
IS ONLINE: true
|
||||
IP ADDRESS: 192.168.43.247
|
||||
APPLICATION NAME: myApp
|
||||
UUID: 59d7700755ec5de06783eda8034c9d3d
|
||||
SUPERVISOR VERSION: 11.14.0
|
||||
OS VERSION: balenaOS 2.58.3+rev1
|
||||
```
|
||||
|
||||
It's time to deploy code to the device.
|
||||
|
||||
### Deploy a project
|
||||
|
||||
Application release images are built on the local machine using the balena CLI.
|
||||
Ensure the root certificate has been correctly installed on the local machine,
|
||||
as discussed above.
|
||||
|
||||
Let's create a trivial project that logs "Idling...". On an empty directory,
|
||||
create a new file named `Dockerfile.template` with the following contents:
|
||||
|
||||
```dockerfile
|
||||
FROM balenalib/%%BALENA_MACHINE_NAME%%-alpine
|
||||
|
||||
CMD [ "balena-idle" ]
|
||||
```
|
||||
|
||||
Then build and deploy the project with:
|
||||
|
||||
```bash
|
||||
balena deploy myApp --logs
|
||||
```
|
||||
|
||||
The project will have been successfully built when a friendly unicorn appears in
|
||||
the terminal:
|
||||
|
||||
```bash
|
||||
[Info] Compose file detected
|
||||
...
|
||||
[Info] Creating release...
|
||||
[Info] Pushing images to registry...
|
||||
[Info] Saving release...
|
||||
[Success] Deploy succeeded!
|
||||
[Success] Release: f62a74c220b92949ec78761c74366046
|
||||
|
||||
\
|
||||
\
|
||||
\\
|
||||
\\
|
||||
>\/7
|
||||
_.-(6' \
|
||||
(=___._/` \
|
||||
) \ |
|
||||
/ / |
|
||||
/ > /
|
||||
j < _\
|
||||
_.-' : ``.
|
||||
\ r=._\ `.
|
||||
<`\\_ \ .`-.
|
||||
\ r-7 `-. ._ ' . `\
|
||||
\`, `-.`7 7) )
|
||||
\/ \| \' / `-._
|
||||
|| .'
|
||||
\\ (
|
||||
>\ >
|
||||
,.-' >.'
|
||||
<.'_.''
|
||||
<'
|
||||
```
|
||||
|
||||
This command packages up the local directory, creates a new Docker image from
|
||||
it and pushes it to the openBalena server. In turn, the server will deploy it to
|
||||
all provisioned devices and within a couple of minutes, they will all run the
|
||||
new release. Logs can be viewed with:
|
||||
|
||||
```bash
|
||||
balena logs 59d7700 --tail
|
||||
[Logs] [10/28/2020, 11:40:16 AM] Supervisor starting
|
||||
[Logs] [10/28/2020, 11:40:50 AM] Creating network 'default'
|
||||
[Logs] [10/28/2020, 11:42:38 AM] Creating volume 'resin-data'
|
||||
[Logs] [10/28/2020, 11:42:40 AM] Downloading image …
|
||||
…
|
||||
[Logs] [10/28/2020, 11:44:00 AM] [main] Idling...
|
||||
```
|
||||
|
||||
Enjoy Balenafying All the Things!
|
14
docs/03-next-steps.md
Normal file
14
docs/03-next-steps.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Next steps
|
||||
|
||||
- Try out [local mode](https://www.balena.io/docs/learn/develop/local-mode),
|
||||
which allows you to build and sync code to your device locally for rapid
|
||||
development.
|
||||
- Develop an application with [multiple containers](https://www.balena.io/docs/learn/develop/multicontainer)
|
||||
to provide a more modular approach to application management.
|
||||
- Manage your device fleet with the use of [configuration](https://www.balena.io/docs/learn/manage/configuration/)
|
||||
and [environment](https://www.balena.io/docs/learn/manage/serv-vars/) variables.
|
||||
- Explore our [example projects](https://balena.io/blog/tags/etcher-featured/)
|
||||
to give you an idea of more things you can do with balena.
|
||||
- If you find yourself stuck or confused, help is just [a click away](https://www.balena.io/support).
|
||||
- Pin selected devices to selected code releases using
|
||||
[sample scripts](https://github.com/balena-io-examples/staged-releases).
|
17
docs/04-differences-openbalena-balenacloud.md
Normal file
17
docs/04-differences-openbalena-balenacloud.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Differences between openBalena and balenaCloud
|
||||
|
||||
| openBalena | balenaCloud |
|
||||
| ----- | ---- |
|
||||
| Device updates using full images | Device updates using [delta images](https://www.balena.io/docs/learn/deploy/delta/) |
|
||||
| Support for a single user | Support for [multiple users](https://www.balena.io/docs/learn/manage/account/#application-members) |
|
||||
| Self-hosted deployment and scaling | balena-managed scaling and deployment |
|
||||
| Community support via [forums][forums] | Private support on [paid plans](https://www.balena.io/pricing/) |
|
||||
| Deploy via `balena deploy` only | Build remotely with native builders using [`balena push`](https://www.balena.io/docs/learn/deploy/deployment/#balena-push) or [`git push`](https://www.balena.io/docs/learn/deploy/deployment/#git-push) |
|
||||
| No support for building via `git push` | Use the same CI workflow with [`git push`](https://www.balena.io/docs/learn/deploy/deployment/#git-push) |
|
||||
| No public URL support | Serve websites directly from device with [public device URLs](https://www.balena.io/docs/learn/manage/actions/#enable-public-device-url) |
|
||||
| Management via `balena-cli` only | Cloud-based device management dashboard |
|
||||
| Download images from [balena.io][balena-os-website] | Download preconfigured images directly from the dashboard |
|
||||
| No supported remote diagnostics | Remote device diagnostics |
|
||||
| Supported devices: Raspberry Pi family, the Intel NUC, the NVIDIA Jetson TX2, and the balenaFin | All the devices listed in balena's [reference documentation](https://www.balena.io/docs/reference/hardware/devices/) |
|
||||
|
||||
Additionally, refer back to the [roadmap](#roadmap) above for planned but not yet implemented features.
|
13
docs/05-roadmap.md
Normal file
13
docs/05-roadmap.md
Normal file
@ -0,0 +1,13 @@
|
||||
# openbalena roadmap
|
||||
|
||||
OpenBalena is currently in beta. While fully functional, it lacks features we
|
||||
consider important before we can comfortably call it production-ready. During
|
||||
this phase, don’t be alarmed if things don’t work as expected just yet (and
|
||||
please let us know about any bugs or errors you encounter!). The following
|
||||
improvements and new functionality is planned:
|
||||
|
||||
- Full documentation
|
||||
- Full test suite
|
||||
- Simplified deployment
|
||||
- Remote host OS updates
|
||||
- Support for custom device types
|
BIN
docs/assets/balenaOS-components.png
Normal file
BIN
docs/assets/balenaOS-components.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
docs/assets/balenaOS-read-only-rootfs.png
Normal file
BIN
docs/assets/balenaOS-read-only-rootfs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 KiB |
BIN
docs/assets/image-partition-layout.png
Normal file
BIN
docs/assets/image-partition-layout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
@ -1,6 +0,0 @@
|
||||
FROM haproxy:1.8-alpine
|
||||
|
||||
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
|
||||
COPY entry.sh /open-balena-entry
|
||||
|
||||
CMD /open-balena-entry
|
@ -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
|
3
package-lock.json
generated
3
package-lock.json
generated
@ -1,3 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
15
repo.yml
15
repo.yml
@ -1,2 +1,15 @@
|
||||
type: 'generic'
|
||||
type: "generic"
|
||||
reviewers: 1
|
||||
upstream:
|
||||
- repo: open-balena-api
|
||||
url: https://github.com/balena-io/open-balena-api
|
||||
- repo: open-balena-vpn
|
||||
url: https://github.com/balena-io/open-balena-vpn
|
||||
- repo: open-balena-registry
|
||||
url: https://github.com/balena-io/open-balena-registry
|
||||
- repo: open-balena-db
|
||||
url: https://github.com/balena-io/open-balena-db
|
||||
- repo: open-balena-s3
|
||||
url: https://github.com/balena-io/open-balena-s3
|
||||
- repo: balena-mdns-publisher
|
||||
url: https://github.com/balena-io/balena-mdns-publisher
|
||||
|
35
scripts/_realpath
Normal file
35
scripts/_realpath
Normal file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
echo_error() {
|
||||
local RED=`tput setaf 1`
|
||||
local RESET=`tput sgr0`
|
||||
echo "${RED}ERROR: ${1}${RESET}"
|
||||
}
|
||||
|
||||
REALPATH=
|
||||
REALPATHS=(
|
||||
'realpath'
|
||||
'grealpath'
|
||||
'greadlink -f'
|
||||
)
|
||||
for cmd in "${REALPATHS[@]}"; do
|
||||
if command -v "${cmd%% *}" &>/dev/null; then
|
||||
REALPATH="${cmd}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${REALPATH}" ]; then
|
||||
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
|
||||
|
||||
realpath() {
|
||||
echo $(command ${REALPATH} "$@")
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
source "${BASH_SOURCE%/*}/_realpath"
|
||||
|
||||
CMD="$(realpath "$0")"
|
||||
DIR="$(dirname "${CMD}")"
|
||||
BASE_DIR="$(dirname "${DIR}")"
|
||||
@ -9,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'
|
||||
@ -16,9 +24,17 @@ if [ ! -f "$ENV_FILE" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "${ENV_FILE}"
|
||||
|
||||
# only include the MDNS publisher IF the domain is valid...
|
||||
if [ ${OPENBALENA_HOST_NAME: -6} == ".local" ]; then
|
||||
INCLUDE_MDNS="-f ${BASE_DIR}/compose/mdns.yml"
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "${ENV_FILE}"; docker-compose \
|
||||
source "${VERSIONS_FILE}"; docker-compose \
|
||||
--project-name 'openbalena' \
|
||||
-f "${BASE_DIR}/compose/services.yml" \
|
||||
${INCLUDE_MDNS} \
|
||||
-f "${CONFIG_DIR}/docker-compose.yml" \
|
||||
"$@"
|
||||
|
@ -18,6 +18,8 @@ echo_bold() {
|
||||
printf "\\033[1m%s\\033[0m\\n" "${@}"
|
||||
}
|
||||
|
||||
source "${BASH_SOURCE%/*}/_realpath"
|
||||
|
||||
CMD="$(realpath "$0")"
|
||||
DIR="$(dirname "${CMD}")"
|
||||
FIG="${DIR}/compose"
|
||||
|
@ -22,12 +22,14 @@ OUT="$(realpath "${2:-.}")"
|
||||
# shellcheck source=scripts/ssl-common.sh
|
||||
source "${DIR}/ssl-common.sh"
|
||||
|
||||
# Create a secret key and CA file for the self-signed CA
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" init-pki 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" --days="${CA_EXPIRY_DAYS}" --req-cn="ca.${CN}" build-ca nopass 2>/dev/null
|
||||
ROOT_CA="${ROOT_PKI}/ca.crt"
|
||||
echo "ROOT_CA=${ROOT_CA//$OUT/\$OUT}"
|
||||
|
||||
# update indexes and generate CRLs
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" update-db 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" gen-crl 2>/dev/null
|
||||
if [ ! -f $ROOT_CA ]; then
|
||||
# Create a secret key and CA file for the self-signed CA
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" init-pki 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" --days="${CA_EXPIRY_DAYS}" --req-cn="ca.${CN}" build-ca nopass 2>/dev/null
|
||||
|
||||
# update indexes and generate CRLs
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" update-db 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" gen-crl 2>/dev/null
|
||||
fi
|
@ -22,13 +22,15 @@ OUT="$(realpath "${2:-.}")"
|
||||
# shellcheck source=scripts/ssl-common.sh
|
||||
source "${DIR}/ssl-common.sh"
|
||||
|
||||
# generate default CSR and sign (root + wildcard)
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" --days="${CRT_EXPIRY_DAYS}" --subject-alt-name="DNS:*.${CN}" build-server-full "*.${CN}" nopass 2>/dev/null
|
||||
ROOT_CRT="${ROOT_PKI}"'/issued/*.'"${CN}"'.crt'
|
||||
ROOT_KEY="${ROOT_PKI}"'/private/*.'"${CN}"'.key'
|
||||
echo "ROOT_CRT=${ROOT_CRT//$OUT/\$OUT}"
|
||||
echo "ROOT_KEY=${ROOT_KEY//$OUT/\$OUT}"
|
||||
|
||||
# update indexes and generate CRLs
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" update-db 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" gen-crl 2>/dev/null
|
||||
if [ ! -f $ROOT_CRT ] || [ ! -f $ROOT_KEY ]; then
|
||||
rm -f $ROOT_CRT $ROOT_KEY
|
||||
# generate default CSR and sign (root + wildcard)
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" --days="${CRT_EXPIRY_DAYS}" --subject-alt-name="DNS:*.${CN}" build-server-full "*.${CN}" nopass 2>/dev/null
|
||||
|
||||
# update indexes and generate CRLs
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" update-db 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${ROOT_PKI}" gen-crl 2>/dev/null
|
||||
fi;
|
||||
|
@ -42,13 +42,12 @@ JWT_CRT="${CERT_FILE}.crt"
|
||||
JWT_KEY="${CERT_FILE}.pem"
|
||||
JWT_KID="${CERT_FILE}.kid"
|
||||
|
||||
mkdir -p "${CERT_DIR}"
|
||||
openssl ecparam -name prime256v1 -genkey -noout -out "${JWT_KEY}" 2>/dev/null
|
||||
openssl req -x509 -new -nodes -days "${CRT_EXPIRY_DAYS}" -key "${JWT_KEY}" -subj "/CN=api.${CN}" -out "${JWT_CRT}" 2>/dev/null
|
||||
openssl ec -in "${JWT_KEY}" -pubout -outform DER -out "${CERT_FILE}.der" 2>/dev/null
|
||||
keyid "${CERT_FILE}.der" >"${JWT_KID}"
|
||||
rm "${CERT_FILE}.der"
|
||||
|
||||
echo "JWT_CRT=${JWT_CRT//$OUT/\$OUT}"
|
||||
echo "JWT_KEY=${JWT_KEY//$OUT/\$OUT}"
|
||||
echo "JWT_KID=${JWT_KID//$OUT/\$OUT}"
|
||||
if [ ! -f $JWT_CRT ] || [ ! -f $JWT_KEY ] || [ ! -f $JWT_KID ]; then
|
||||
rm -f $JWT_CRT $JWT_KEY $JWT_KID
|
||||
mkdir -p "${CERT_DIR}"
|
||||
openssl ecparam -name prime256v1 -genkey -noout -out "${JWT_KEY}" 2>/dev/null
|
||||
openssl req -x509 -new -nodes -days "${CRT_EXPIRY_DAYS}" -key "${JWT_KEY}" -subj "/CN=api.${CN}" -out "${JWT_CRT}" 2>/dev/null
|
||||
openssl ec -in "${JWT_KEY}" -pubout -outform DER -out "${CERT_FILE}.der" 2>/dev/null
|
||||
keyid "${CERT_FILE}.der" >"${JWT_KID}"
|
||||
rm "${CERT_FILE}.der"
|
||||
fi
|
||||
|
@ -21,33 +21,28 @@ OUT="$(realpath "${2:-.}")"
|
||||
|
||||
# shellcheck source=scripts/ssl-common.sh
|
||||
source "${DIR}/ssl-common.sh"
|
||||
|
||||
VPN_PKI="$(realpath "${OUT}/vpn")"
|
||||
|
||||
# generate VPN sub-CA
|
||||
"$easyrsa_bin" --pki-dir="${VPN_PKI}" init-pki 2>/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"
|
||||
VPN_CA="${VPN_PKI}/ca.crt"
|
||||
echo "VPN_CA=${VPN_CA//$OUT/\$OUT}"
|
||||
|
||||
# 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
|
||||
VPN_CRT="${VPN_PKI}/issued/vpn.${CN}.crt"
|
||||
VPN_KEY="${VPN_PKI}/private/vpn.${CN}.key"
|
||||
echo "VPN_CRT=${VPN_CRT//$OUT/\$OUT}"
|
||||
echo "VPN_KEY=${VPN_KEY//$OUT/\$OUT}"
|
||||
|
||||
# generate vpn dhparams (keysize of 2048 will do, 4096 can wind up taking hours to generate)
|
||||
"$easyrsa_bin" --pki-dir="${VPN_PKI}" --keysize=2048 gen-dh 2>/dev/null
|
||||
VPN_DH="${VPN_PKI}/dh.pem"
|
||||
echo "VPN_DH=${VPN_DH//$OUT/\$OUT}"
|
||||
|
||||
# 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
|
||||
if [ ! -f $VPN_CA ] || [ ! -f $VPN_CRT ] || [ ! -f $VPN_KEY ] || [ ! -f $VPN_DH ]; then
|
||||
|
||||
rm -f $VPN_CA $VPN_CRT $VPN_DH $VPN_KEY
|
||||
|
||||
# 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 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
|
||||
|
||||
# generate vpn dhparams (keysize of 2048 will do, 4096 can wind up taking hours to generate)
|
||||
"$easyrsa_bin" --pki-dir="${VPN_PKI}" --keysize=2048 gen-dh 2>/dev/null
|
||||
|
||||
# update indexes and generate CRLs
|
||||
"$easyrsa_bin" --pki-dir="${VPN_PKI}" update-db 2>/dev/null
|
||||
"$easyrsa_bin" --pki-dir="${VPN_PKI}" gen-crl 2>/dev/null
|
||||
fi
|
62
scripts/logger.sh
Normal file
62
scripts/logger.sh
Normal file
@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
|
||||
BLACK=`tput setaf 0`
|
||||
RED=`tput setaf 1`
|
||||
GREEN=`tput setaf 2`
|
||||
YELLOW=`tput setaf 3`
|
||||
BLUE=`tput setaf 4`
|
||||
MAGENTA=`tput setaf 5`
|
||||
CYAN=`tput setaf 6`
|
||||
WHITE=`tput setaf 7`
|
||||
|
||||
BOLD=`tput bold`
|
||||
RESET=`tput sgr0`
|
||||
|
||||
log_raw () {
|
||||
local COLOR="${WHITE}"
|
||||
local LEVEL="${1}"
|
||||
local MESSAGE="${2}"
|
||||
case "${LEVEL}" in
|
||||
info)
|
||||
COLOR="${BLUE}"
|
||||
;;
|
||||
warn)
|
||||
COLOR="${YELLOW}"
|
||||
;;
|
||||
fatal)
|
||||
COLOR="${RED}"
|
||||
;;
|
||||
*)
|
||||
LEVEL="debug"
|
||||
;;
|
||||
esac
|
||||
LEVEL="${LEVEL} "
|
||||
echo "[$(date +%T)] ${COLOR}$(echo "${LEVEL:0:5}" | tr '[:lower:]' '[:upper:]')${RESET} ${MESSAGE}";
|
||||
}
|
||||
|
||||
log () {
|
||||
log_raw "debug" "${1}"
|
||||
}
|
||||
|
||||
info () {
|
||||
log_raw "info" "${1}";
|
||||
}
|
||||
|
||||
warn () {
|
||||
log_raw "warn" "${1}";
|
||||
}
|
||||
|
||||
die () {
|
||||
log_raw "fatal" "${1}";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
die_unless_forced () {
|
||||
if [ ! -z "$1" ]; then
|
||||
log_raw "warn" "$2";
|
||||
return;
|
||||
fi
|
||||
|
||||
log_raw "fatal" "$2";
|
||||
die "Use -f to forcibly upgrade.";
|
||||
}
|
@ -12,10 +12,12 @@ 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"
|
||||
echo " SUPERUSER_EMAIL Email address of the superuser"
|
||||
echo " SUPERUSER_PASSWORD Password of the superuser"
|
||||
echo
|
||||
}
|
||||
|
||||
@ -31,61 +33,45 @@ randstr() {
|
||||
}
|
||||
|
||||
b64encode() {
|
||||
cat "$@" | base64 --wrap=0 2>/dev/null || cat "$@" | base64 --break=0
|
||||
echo "$@" | base64 --wrap=0 2>/dev/null || echo "$@" | base64 --break=0 2>/dev/null
|
||||
}
|
||||
|
||||
VPN_CONFIG=$(b64encode <<STR
|
||||
client
|
||||
remote vpn.$DOMAIN 443
|
||||
resolv-retry infinite
|
||||
b64file() {
|
||||
b64encode "$(cat "$@")"
|
||||
}
|
||||
|
||||
remote-cert-tls server
|
||||
ca /etc/openvpn/ca.crt
|
||||
auth-user-pass /var/volatile/vpn-auth
|
||||
auth-retry none
|
||||
script-security 2
|
||||
up /etc/openvpn-misc/upscript.sh
|
||||
up-restart
|
||||
down /etc/openvpn-misc/downscript.sh
|
||||
|
||||
comp-lzo
|
||||
dev resin-vpn
|
||||
dev-type tun
|
||||
proto tcp
|
||||
nobind
|
||||
|
||||
persist-key
|
||||
persist-tun
|
||||
verb 3
|
||||
user openvpn
|
||||
group openvpn
|
||||
STR
|
||||
)
|
||||
# buckets to create in the S3 service...
|
||||
REGISTRY2_S3_BUCKET="registry-data"
|
||||
|
||||
cat <<STR
|
||||
export OPENBALENA_PRODUCTION_MODE=false
|
||||
export OPENBALENA_COOKIE_SESSION_SECRET=$(randstr 32)
|
||||
export OPENBALENA_HOST_NAME=$DOMAIN
|
||||
export OPENBALENA_JWT_SECRET=$(randstr 32)
|
||||
export OPENBALENA_REGISTRY2_S3_BUCKET=${REGISTRY2_S3_BUCKET}
|
||||
export OPENBALENA_RESINOS_REGISTRY_CODE=$(randstr 32)
|
||||
export OPENBALENA_ROOT_CA=$(b64encode "$ROOT_CA")
|
||||
export OPENBALENA_ROOT_CRT=$(b64encode "${ROOT_CRT}")
|
||||
export OPENBALENA_ROOT_KEY=$(b64encode "${ROOT_KEY}")
|
||||
export OPENBALENA_ROOT_CA=$(b64file "${ROOT_CA}")
|
||||
export OPENBALENA_ROOT_CRT=$(b64file "${ROOT_CRT}")
|
||||
export OPENBALENA_ROOT_KEY=$(b64file "${ROOT_KEY}")
|
||||
export OPENBALENA_TOKEN_AUTH_BUILDER_TOKEN=$(randstr 64)
|
||||
export OPENBALENA_TOKEN_AUTH_PUB=$(b64encode "$JWT_CRT")
|
||||
export OPENBALENA_TOKEN_AUTH_KEY=$(b64encode "$JWT_KEY")
|
||||
export OPENBALENA_TOKEN_AUTH_KID=$(b64encode "$JWT_KID")
|
||||
export OPENBALENA_VPN_CA=$(b64encode "$VPN_CA")
|
||||
export OPENBALENA_VPN_CA_CHAIN=$(b64encode "$ROOT_CA" "$VPN_CA")
|
||||
export OPENBALENA_VPN_CONFIG=$VPN_CONFIG
|
||||
export OPENBALENA_VPN_SERVER_CRT=$(b64encode "$VPN_CRT")
|
||||
export OPENBALENA_VPN_SERVER_KEY=$(b64encode "$VPN_KEY")
|
||||
export OPENBALENA_VPN_SERVER_DH=$(b64encode "$VPN_DH")
|
||||
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 "$VPN_CA")
|
||||
export OPENBALENA_VPN_SERVER_CRT=$(b64file "$VPN_CRT")
|
||||
export OPENBALENA_VPN_SERVER_KEY=$(b64file "$VPN_KEY")
|
||||
export OPENBALENA_VPN_SERVER_DH=$(b64file "$VPN_DH")
|
||||
export OPENBALENA_VPN_SERVICE_API_KEY=$(randstr 32)
|
||||
export OPENBALENA_API_VPN_SERVICE_API_KEY=$(randstr 32)
|
||||
export OPENBALENA_REGISTRY_SECRET_KEY=$(randstr 32)
|
||||
export OPENBALENA_S3_ACCESS_KEY=$(randstr 32)
|
||||
export OPENBALENA_S3_BUCKETS="${REGISTRY2_S3_BUCKET}"
|
||||
export OPENBALENA_S3_ENDPOINT="https://s3.${DOMAIN}"
|
||||
export OPENBALENA_S3_REGION=us-east-1
|
||||
export OPENBALENA_S3_SECRET_KEY=$(randstr 32)
|
||||
export OPENBALENA_SSH_AUTHORIZED_KEYS=
|
||||
export NODE_EXTRA_CA_CERTS="$ROOT_CA"
|
||||
export OPENBALENA_SUPERUSER_EMAIL=$SUPERUSER_EMAIL
|
||||
export OPENBALENA_SUPERUSER_PASSWORD=$SUPERUSER_PASSWORD
|
||||
export OPENBALENA_SUPERUSER_PASSWORD=$(printf "%q" "${SUPERUSER_PASSWORD}")
|
||||
export OPENBALENA_ACME_CERT_ENABLED=${ACME_CERT_ENABLED:-false}
|
||||
STR
|
||||
|
29
scripts/migrate-registry-storage
Executable file
29
scripts/migrate-registry-storage
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
migrate_data_to_s3 () {
|
||||
BUCKET="${1:-registry-data}"
|
||||
|
||||
if [ -z "${BUCKET}" ]; then return 1; fi
|
||||
|
||||
if [ -n "${DOCKER_HOST}" ]; then
|
||||
log "Using docker host: ${DOCKER_HOST}"
|
||||
export DOCKER_HOST="${DOCKER_HOST}"
|
||||
fi
|
||||
|
||||
REGISTRY_CONTAINER="$(docker ps | grep registry_ | awk '{print $1}')"
|
||||
S3_CONTAINER="$(docker ps | grep s3_ | awk '{print $1}')"
|
||||
|
||||
if [ -z "${REGISTRY_CONTAINER}" ] || [ -z "${S3_CONTAINER}" ]; then return 2; fi
|
||||
|
||||
REGISTRY_VOLUME="$(docker inspect "${REGISTRY_CONTAINER}" | jq -r '.[].Mounts | map(select(.Destination=="/data")) | .[0].Source')"
|
||||
S3_VOLUME=$(docker inspect "${S3_CONTAINER}" | jq -r '.[].Mounts | map(select(.Destination=="/export")) | .[0].Source')
|
||||
|
||||
if [ -z "${REGISTRY_VOLUME}" ] || [ -z "${S3_VOLUME}" ]; then return 3; fi
|
||||
|
||||
# run the S3 container image, and copy the data partition into S3...
|
||||
docker run -it --rm \
|
||||
-v "${REGISTRY_VOLUME}:/data" \
|
||||
-v "${S3_VOLUME}:/s3" \
|
||||
--name "migrate-registry" alpine \
|
||||
sh -c "mkdir -p /s3/${BUCKET}/data && cp -r /data/docker /s3/${BUCKET}/data/"
|
||||
}
|
@ -1,5 +1,36 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
BLACK=`tput setaf 0`
|
||||
RED=`tput setaf 1`
|
||||
GREEN=`tput setaf 2`
|
||||
YELLOW=`tput setaf 3`
|
||||
BLUE=`tput setaf 4`
|
||||
MAGENTA=`tput setaf 5`
|
||||
CYAN=`tput setaf 6`
|
||||
WHITE=`tput setaf 7`
|
||||
|
||||
BOLD=`tput bold`
|
||||
RESET=`tput sgr0`
|
||||
|
||||
# for macos machines, we need proper OpenSSL...
|
||||
OPENSSL_VERSION=$(openssl version -v)
|
||||
if [[ "${OPENSSL_VERSION}" =~ ^LibreSSL.*$ ]]; then
|
||||
echo -e "${RED}ERROR: You may not have a compatible OpenSSL version (${OPENSSL_VERSION}). Please install OpenSSL version 1.0.2q or above.${RESET}"
|
||||
if [ $(uname) == 'Darwin' ]; then
|
||||
echo 'OpenSSL is required to build openBalena on macOS. To install with brew, run'
|
||||
echo ''
|
||||
echo ' brew install openssl'
|
||||
echo ''
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "${BASH_SOURCE%/*}/_realpath"
|
||||
|
||||
domainResolves() {
|
||||
getent hosts "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
CMD="$(realpath "$0")"
|
||||
DIR="$(dirname "${CMD}")"
|
||||
BASE_DIR="$(dirname "${DIR}")"
|
||||
@ -9,8 +40,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"
|
||||
@ -20,13 +52,15 @@ usage() {
|
||||
|
||||
show_help=false
|
||||
patch_hosts=false
|
||||
while getopts ":hpd:U:P:" opt; do
|
||||
while getopts ":chpxd:U:P:" opt; do
|
||||
case "${opt}" in
|
||||
h) show_help=true;;
|
||||
p) patch_hosts=true;;
|
||||
x) set -x;;
|
||||
d) DOMAIN="${OPTARG}";;
|
||||
U) SUPERUSER_EMAIL="${OPTARG}";;
|
||||
P) SUPERUSER_PASSWORD="${OPTARG}";;
|
||||
c) ACME_CERT_ENABLED="true";;
|
||||
*)
|
||||
echo "Invalid argument: -${OPTARG}"
|
||||
usage
|
||||
@ -46,18 +80,25 @@ if [ "$show_help" = "true" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo_bold() {
|
||||
printf "\\033[1m%s\\033[0m\\n" "${@}"
|
||||
}
|
||||
|
||||
if [ -d "$CONFIG_DIR" ]; then
|
||||
echo 'Configuration directory already exists; please remove it first.'
|
||||
exit 1
|
||||
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() {
|
||||
echo "${BOLD}${@}${RESET}"
|
||||
}
|
||||
|
||||
echo_bold "==> Creating new configuration at: $CONFIG_DIR"
|
||||
mkdir -p "$CONFIG_DIR" "$CERTS_DIR"
|
||||
|
||||
echo_bold "==> Bootstrapping easy-rsa..."
|
||||
source "${DIR}/ssl-common.sh"
|
||||
|
||||
echo_bold "==> Generating root CA cert..."
|
||||
# shellcheck source=scripts/gen-root-ca
|
||||
source "${DIR}/gen-root-ca" "${DOMAIN}" "${CERTS_DIR}"
|
||||
@ -90,5 +131,25 @@ 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: ${CONFIG_DIR}/root/ca.crt"
|
||||
echo ' - To create a single, flat, docker-compose.yml file, run:'
|
||||
echo ''
|
||||
echo ' ./scripts/compose config > docker-compose.yml'
|
||||
echo ''
|
||||
|
||||
if [ -z "${ACME_CERT_ENABLED}" ]; then
|
||||
echo " - Use the following certificate with Balena CLI: ${CERTS_DIR}/root/ca.crt"
|
||||
|
||||
case $(uname) in
|
||||
Darwin)
|
||||
echo ''
|
||||
printf ' On macOS:\n\n'
|
||||
printf ' sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "%s/root/ca.crt"\n' "${CERTS_DIR}"
|
||||
echo ''
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
echo -e " ${YELLOW}IMPORTANT:${RESET} You will need to restart your Docker daemon after trusting this certificate to allow your workstation to push images to the registry."
|
||||
echo ''
|
||||
fi
|
||||
|
@ -7,6 +7,7 @@ if [ -z "${easyrsa_bin-}" ] || [ ! -x "${easyrsa_bin}" ]; then
|
||||
if [ -z "${easyrsa_bin}" ]; then
|
||||
easyrsa_dir="$(mktemp -dt easyrsa.XXXXXXXX)"
|
||||
easyrsa_url="https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.5/EasyRSA-nix-3.0.5.tgz"
|
||||
echo " - Downloading easy-rsa..."
|
||||
(cd "${easyrsa_dir}"; curl -sL "${easyrsa_url}" | tar xz --strip-components=1)
|
||||
easyrsa_bin="${easyrsa_dir}/easyrsa"
|
||||
# shellcheck disable=SC2064
|
||||
|
78
scripts/upgrade-1.x-to-2.0
Executable file
78
scripts/upgrade-1.x-to-2.0
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
|
||||
source "${BASH_SOURCE%/*}/logger.sh"
|
||||
source "${BASH_SOURCE%/*}/migrate-registry-storage"
|
||||
|
||||
# This script takes a v1.x.x install and updates the compose stack to use S3 as your
|
||||
# registry storage.
|
||||
|
||||
source "${BASH_SOURCE%/*}/_realpath"
|
||||
|
||||
DIR="$(dirname $(realpath "$0"))"
|
||||
BASE_DIR="$(dirname "${DIR}")"
|
||||
CONFIG_DIR="${BASE_DIR}/config"
|
||||
CONFIG_FILE="${CONFIG_DIR}/activate"
|
||||
|
||||
# Step 1. Make sure a config exists...
|
||||
[ -f "${CONFIG_FILE}" ] || die "Unable to find existing config!";
|
||||
|
||||
info "Preparing to upgrade..."
|
||||
source "${CONFIG_FILE}"
|
||||
|
||||
while getopts "f" opt; do
|
||||
case "${opt}" in
|
||||
f)
|
||||
warn "Forcing upgrade! I hope you know what you're doing..."
|
||||
FORCE_UPGRADE=1
|
||||
;;
|
||||
*)
|
||||
echo "Invalid argument: ${OPTARG}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# Step 2. Check if the S3 configuration already exists...
|
||||
upgrade_required () {
|
||||
[ -z "${OPENBALENA_REGISTRY2_S3_BUCKET}" ] || return 1;
|
||||
[ -z "${OPENBALENA_S3_ACCESS_KEY}" ] || return 1;
|
||||
[ -z "${OPENBALENA_S3_ENDPOINT}" ] || return 1;
|
||||
[ -z "${OPENBALENA_S3_REGION}" ] || return 1;
|
||||
[ -z "${OPENBALENA_S3_SECRET_KEY}" ] || return 1;
|
||||
}
|
||||
upgrade_required || die_unless_forced "${FORCE_UPGRADE}" "Configuration may already be using S3 for Registry storage!"
|
||||
|
||||
# Step 3. Create missing S3 configuration...
|
||||
randstr() {
|
||||
LC_CTYPE=C tr -dc A-Za-z0-9 < /dev/urandom | fold -w "${1:-32}" | head -n 1
|
||||
}
|
||||
|
||||
upsert_config () {
|
||||
var="${1}"
|
||||
value="${2}"
|
||||
|
||||
if [ -z "${!var}" ]; then
|
||||
echo "export ${1}=${2}" >> "${CONFIG_FILE}"
|
||||
else
|
||||
sed -i '' "s~export ${1}=.*~export ${1}=${2}~" "${CONFIG_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
upsert_config "OPENBALENA_REGISTRY2_S3_BUCKET" "registry-data" || warn "Failed to update config value OPENBALENA_REGISTRY2_S3_BUCKET"
|
||||
upsert_config "OPENBALENA_S3_ACCESS_KEY" "$(randstr 32)" || warn "Failed to update config value OPENBALENA_S3_ACCESS_KEY"
|
||||
upsert_config "OPENBALENA_S3_ENDPOINT" "https://s3.${OPENBALENA_HOST_NAME}" || warn "Failed to update config value OPENBALENA_S3_ENDPOINT"
|
||||
upsert_config "OPENBALENA_S3_REGION" "us-east-1" || warn "Failed to update config value OPENBALENA_S3_REGION"
|
||||
upsert_config "OPENBALENA_S3_SECRET_KEY" "$(randstr 32)" || warn "Failed to update config value OPENBALENA_S3_SECRET_KEY"
|
||||
|
||||
# Step 4. Migrate Registry data to S3...
|
||||
info "Copying data from the Registry volume to the S3 volume..."
|
||||
migrate_data_to_s3 "registry-data"
|
||||
case $? in
|
||||
1) die "Invalid bucket name";;
|
||||
2) die "Unable to find the running Registry or S3 containers";;
|
||||
3) die "Unable to determine the data volumes for the Registry or S3 containers";;
|
||||
*) info "Registry data copied"
|
||||
;;
|
||||
esac
|
||||
info "Upgrade complete"
|
22
src/cert-provider/Dockerfile
Normal file
22
src/cert-provider/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
||||
FROM alpine
|
||||
|
||||
EXPOSE 80
|
||||
WORKDIR /usr/src/app
|
||||
VOLUME [ "/usr/src/app/certs" ]
|
||||
|
||||
RUN apk add --update bash curl git openssl ncurses socat
|
||||
|
||||
# from https://github.com/Neilpang/acme.sh/releases/tag/3.0.1
|
||||
RUN git clone https://github.com/Neilpang/acme.sh.git && \
|
||||
cd acme.sh && \
|
||||
git fetch && git fetch --tags && \
|
||||
git checkout 3.0.1 . && \
|
||||
./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" ]
|
190
src/cert-provider/cert-provider.sh
Executable file
190
src/cert-provider/cert-provider.sh
Executable file
@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env 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
|
||||
(( ATTEMPT++ ))
|
||||
logInfo "($ATTEMPT/$RETRIES) Connecting..."
|
||||
if $1; then
|
||||
logInfo "($ATTEMPT/$RETRIES) Success!"
|
||||
return $?
|
||||
fi
|
||||
|
||||
if [ "$RETRIES" -gt "$ATTEMPT" ]; then
|
||||
logInfo "($ATTEMPT/$RETRIES) Failed. Retrying in ${DELAY} seconds..."
|
||||
sleep "$DELAY"
|
||||
else
|
||||
logInfo "($ATTEMPT/$RETRIES) Failed!"
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
waitForOnline() {
|
||||
ADDRESS="${1,,}"
|
||||
|
||||
logInfo "Waiting for ${ADDRESS} to be available via HTTP..."
|
||||
retryWithDelay "curl --output /dev/null --silent --head --fail --max-time 5 http://${ADDRESS}"
|
||||
}
|
||||
|
||||
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" --server letsencrypt --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."
|
||||
|
||||
while ! waitForOnline "${ACME_DOMAINS[0]}"; do
|
||||
logInfo "Unable to access ${ACME_DOMAINS[0]} on port 80. This is needed for certificate validation. Retrying in 30 seconds..."
|
||||
sleep 30
|
||||
done
|
||||
|
||||
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
src/cert-provider/entry.sh
Executable file
3
src/cert-provider/entry.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
exec "$@"
|
119
src/cert-provider/fake-le-bundle.pem
Normal file
119
src/cert-provider/fake-le-bundle.pem
Normal file
@ -0,0 +1,119 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIRALqMZiRNaRF4EGZS9urlj+0wDQYJKoZIhvcNAQELBQAw
|
||||
cTELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1
|
||||
cml0eSBSZXNlYXJjaCBHcm91cDEtMCsGA1UEAxMkKFNUQUdJTkcpIERvY3RvcmVk
|
||||
IER1cmlhbiBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDEzMDE0MDEx
|
||||
NVowcTELMAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBT
|
||||
ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEtMCsGA1UEAxMkKFNUQUdJTkcpIERvY3Rv
|
||||
cmVkIER1cmlhbiBSb290IENBIFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAqUZjoRbjgXecPWxXkGCUEXcNrupL7dkbwc0jUTLFEDvcyfD1gYekY5uL
|
||||
D19uzYTl0pKZzzDXHJPnJY5EEp27nACFOm8XzX9sORAangP0OnGUkXJZDHM+8cX2
|
||||
EHJbfj0lg1JirRF3w2u1/KRuFEvIlWg3FdXdsSFHBF5z1Ij7MLn7Ska5c/5fKsDW
|
||||
EYzOMB6EBW1T9RDkVk/Q965EwDT4bR6BOXakasgfKrH9m1f6l9MmA0VnXdw9rZ+s
|
||||
TvMHG1yWBqNMSqCKe3jG6caWgN7llEbj5YsCWs32bz2dMftGkXBPcy1fNWvpeT7G
|
||||
Dz2Z0QWTlHkyXA2kGw32fdoXLHWOEwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYw
|
||||
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCFfaiceiU3kMT93gkI90uuInc0Qw
|
||||
DQYJKoZIhvcNAQELBQADggEBAF7lEtHuSN4j+xFQsM/ujaVKcn57VbrbTecnspmJ
|
||||
JA7Hrn6OErshGNO0p1/u14c7tGHKjtF1tEFFSVhbNXlKw9O99AfhmlFgdGcJKEHn
|
||||
ZctBB8bhNO387vbiCYIHdU/nSba9MCDYw2/UCtobZ6ao+KJA3IKmPixctAbn2Ikr
|
||||
EN9X0SXNP1gnqQP4VhZJIh6cd7rg9MimzoLlMI3m2z11dSGYbh8OWSdvA7aLbSGo
|
||||
gDO5H4WD8fgqEG0reSBO89eeH+we+BZxQtBiU3b9VMV0drc+7zC2NbXqeQwu6QTl
|
||||
fbJ8ytqcqUy0g5XSE6WCzPOL3H9r0j9G64dfotGlBA5tG6w=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFmDCCA4CgAwIBAgIQU9C87nMpOIFKYpfvOHFHFDANBgkqhkiG9w0BAQsFADBm
|
||||
MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy
|
||||
aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ
|
||||
ZWFyIFgxMB4XDTE1MDYwNDExMDQzOFoXDTM1MDYwNDExMDQzOFowZjELMAkGA1UE
|
||||
BhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0eSBSZXNl
|
||||
YXJjaCBHcm91cDEiMCAGA1UEAxMZKFNUQUdJTkcpIFByZXRlbmQgUGVhciBYMTCC
|
||||
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALbagEdDTa1QgGBWSYkyMhsc
|
||||
ZXENOBaVRTMX1hceJENgsL0Ma49D3MilI4KS38mtkmdF6cPWnL++fgehT0FbRHZg
|
||||
jOEr8UAN4jH6omjrbTD++VZneTsMVaGamQmDdFl5g1gYaigkkmx8OiCO68a4QXg4
|
||||
wSyn6iDipKP8utsE+x1E28SA75HOYqpdrk4HGxuULvlr03wZGTIf/oRt2/c+dYmD
|
||||
oaJhge+GOrLAEQByO7+8+vzOwpNAPEx6LW+crEEZ7eBXih6VP19sTGy3yfqK5tPt
|
||||
TdXXCOQMKAp+gCj/VByhmIr+0iNDC540gtvV303WpcbwnkkLYC0Ft2cYUyHtkstO
|
||||
fRcRO+K2cZozoSwVPyB8/J9RpcRK3jgnX9lujfwA/pAbP0J2UPQFxmWFRQnFjaq6
|
||||
rkqbNEBgLy+kFL1NEsRbvFbKrRi5bYy2lNms2NJPZvdNQbT/2dBZKmJqxHkxCuOQ
|
||||
FjhJQNeO+Njm1Z1iATS/3rts2yZlqXKsxQUzN6vNbD8KnXRMEeOXUYvbV4lqfCf8
|
||||
mS14WEbSiMy87GB5S9ucSV1XUrlTG5UGcMSZOBcEUpisRPEmQWUOTWIoDQ5FOia/
|
||||
GI+Ki523r2ruEmbmG37EBSBXdxIdndqrjy+QVAmCebyDx9eVEGOIpn26bW5LKeru
|
||||
mJxa/CFBaKi4bRvmdJRLAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
|
||||
Af8EBTADAQH/MB0GA1UdDgQWBBS182Xy/rAKkh/7PH3zRKCsYyXDFDANBgkqhkiG
|
||||
9w0BAQsFAAOCAgEAncDZNytDbrrVe68UT6py1lfF2h6Tm2p8ro42i87WWyP2LK8Y
|
||||
nLHC0hvNfWeWmjZQYBQfGC5c7aQRezak+tHLdmrNKHkn5kn+9E9LCjCaEsyIIn2j
|
||||
qdHlAkepu/C3KnNtVx5tW07e5bvIjJScwkCDbP3akWQixPpRFAsnP+ULx7k0aO1x
|
||||
qAeaAhQ2rgo1F58hcflgqKTXnpPM02intVfiVVkX5GXpJjK5EoQtLceyGOrkxlM/
|
||||
sTPq4UrnypmsqSagWV3HcUlYtDinc+nukFk6eR4XkzXBbwKajl0YjztfrCIHOn5Q
|
||||
CJL6TERVDbM/aAPly8kJ1sWGLuvvWYzMYgLzDul//rUF10gEMWaXVZV51KpS9DY/
|
||||
5CunuvCXmEQJHo7kGcViT7sETn6Jz9KOhvYcXkJ7po6d93A/jy4GKPIPnsKKNEmR
|
||||
xUuXY4xRdh45tMJnLTUDdC9FIU0flTeO9/vNpVA8OPU1i14vCz+MU8KX1bV3GXm/
|
||||
fxlB7VBBjX9v5oUep0o/j68R/iDlCOM4VVfRa8gX6T2FU7fNdatvGro7uQzIvWof
|
||||
gN9WUwCbEMBy/YhBSrXycKA8crgGg3x1mIsopn88JKwmMBa68oS7EHM9w7C4y71M
|
||||
7DiA+/9Qdp9RBWJpTS9i/mDnJg1xvo8Xz49mrrgfmcAXTCJqXi24NatI3Oc=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICTjCCAdSgAwIBAgIRAIPgc3k5LlLVLtUUvs4K/QcwCgYIKoZIzj0EAwMwaDEL
|
||||
MAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0
|
||||
eSBSZXNlYXJjaCBHcm91cDEkMCIGA1UEAxMbKFNUQUdJTkcpIEJvZ3VzIEJyb2Nj
|
||||
b2xpIFgyMB4XDTIwMDkwNDAwMDAwMFoXDTQwMDkxNzE2MDAwMFowaDELMAkGA1UE
|
||||
BhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0eSBSZXNl
|
||||
YXJjaCBHcm91cDEkMCIGA1UEAxMbKFNUQUdJTkcpIEJvZ3VzIEJyb2Njb2xpIFgy
|
||||
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOvS+w1kCzAxYOJbA06Aw0HFP2tLBLKPo
|
||||
FQqR9AMskl1nC2975eQqycR+ACvYelA8rfwFXObMHYXJ23XLB+dAjPJVOJ2OcsjT
|
||||
VqO4dcDWu+rQ2VILdnJRYypnV1MMThVxo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
|
||||
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3tGjWWQOwZo2o0busBB2766XlWYwCgYI
|
||||
KoZIzj0EAwMDaAAwZQIwRcp4ZKBsq9XkUuN8wfX+GEbY1N5nmCRc8e80kUkuAefo
|
||||
uc2j3cICeXo1cOybQ1iWAjEA3Ooawl8eQyR4wrjCofUE8h44p0j7Yl/kBlJZT8+9
|
||||
vbtH7QiVzeKCOTQPINyRql6P
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFWzCCA0OgAwIBAgIQTfQrldHumzpMLrM7jRBd1jANBgkqhkiG9w0BAQsFADBm
|
||||
MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy
|
||||
aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ
|
||||
ZWFyIFgxMB4XDTIwMDkwNDAwMDAwMFoXDTI1MDkxNTE2MDAwMFowWTELMAkGA1UE
|
||||
BhMCVVMxIDAeBgNVBAoTFyhTVEFHSU5HKSBMZXQncyBFbmNyeXB0MSgwJgYDVQQD
|
||||
Ex8oU1RBR0lORykgQXJ0aWZpY2lhbCBBcHJpY290IFIzMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAu6TR8+74b46mOE1FUwBrvxzEYLck3iasmKrcQkb+
|
||||
gy/z9Jy7QNIAl0B9pVKp4YU76JwxF5DOZZhi7vK7SbCkK6FbHlyU5BiDYIxbbfvO
|
||||
L/jVGqdsSjNaJQTg3C3XrJja/HA4WCFEMVoT2wDZm8ABC1N+IQe7Q6FEqc8NwmTS
|
||||
nmmRQm4TQvr06DP+zgFK/MNubxWWDSbSKKTH5im5j2fZfg+j/tM1bGaczFWw8/lS
|
||||
nukyn5J2L+NJYnclzkXoh9nMFnyPmVbfyDPOc4Y25aTzVoeBKXa/cZ5MM+WddjdL
|
||||
biWvm19f1sYn1aRaAIrkppv7kkn83vcth8XCG39qC2ZvaQIDAQABo4IBEDCCAQww
|
||||
DgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAS
|
||||
BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTecnpI3zHDplDfn4Uj31c3S10u
|
||||
ZTAfBgNVHSMEGDAWgBS182Xy/rAKkh/7PH3zRKCsYyXDFDA2BggrBgEFBQcBAQQq
|
||||
MCgwJgYIKwYBBQUHMAKGGmh0dHA6Ly9zdGcteDEuaS5sZW5jci5vcmcvMCsGA1Ud
|
||||
HwQkMCIwIKAeoByGGmh0dHA6Ly9zdGcteDEuYy5sZW5jci5vcmcvMCIGA1UdIAQb
|
||||
MBkwCAYGZ4EMAQIBMA0GCysGAQQBgt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCN
|
||||
DLam9yN0EFxxn/3p+ruWO6n/9goCAM5PT6cC6fkjMs4uas6UGXJjr5j7PoTQf3C1
|
||||
vuxiIGRJC6qxV7yc6U0X+w0Mj85sHI5DnQVWN5+D1er7mp13JJA0xbAbHa3Rlczn
|
||||
y2Q82XKui8WHuWra0gb2KLpfboYj1Ghgkhr3gau83pC/WQ8HfkwcvSwhIYqTqxoZ
|
||||
Uq8HIf3M82qS9aKOZE0CEmSyR1zZqQxJUT7emOUapkUN9poJ9zGc+FgRZvdro0XB
|
||||
yphWXDaqMYph0DxW/10ig5j4xmmNDjCRmqIKsKoWA52wBTKKXK1na2ty/lW5dhtA
|
||||
xkz5rVZFd4sgS4J0O+zm6d5GRkWsNJ4knotGXl8vtS3X40KXeb3A5+/3p0qaD215
|
||||
Xq8oSNORfB2oI1kQuyEAJ5xvPTdfwRlyRG3lFYodrRg6poUBD/8fNTXMtzydpRgy
|
||||
zUQZh/18F6B/iW6cbiRN9r2Hkh05Om+q0/6w0DdZe+8YrNpfhSObr/1eVZbKGMIY
|
||||
qKmyZbBNu5ysENIK5MPc14mUeKmFjpN840VR5zunoU52lqpLDua/qIM8idk86xGW
|
||||
xx2ml43DO/Ya/tVZVok0mO0TUjzJIfPqyvr455IsIut4RlCR9Iq0EDTve2/ZwCuG
|
||||
hSjpTUFGSiQrR2JK2Evp+o6AETUkBCO1aw0PpQBPDQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCzCCApGgAwIBAgIRALRY4992FVxZJKOJ3bpffWIwCgYIKoZIzj0EAwMwaDEL
|
||||
MAkGA1UEBhMCVVMxMzAxBgNVBAoTKihTVEFHSU5HKSBJbnRlcm5ldCBTZWN1cml0
|
||||
eSBSZXNlYXJjaCBHcm91cDEkMCIGA1UEAxMbKFNUQUdJTkcpIEJvZ3VzIEJyb2Nj
|
||||
b2xpIFgyMB4XDTIwMDkwNDAwMDAwMFoXDTI1MDkxNTE2MDAwMFowVTELMAkGA1UE
|
||||
BhMCVVMxIDAeBgNVBAoTFyhTVEFHSU5HKSBMZXQncyBFbmNyeXB0MSQwIgYDVQQD
|
||||
ExsoU1RBR0lORykgRXJzYXR6IEVkYW1hbWUgRTEwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAT9v/PJUtHOTk28nXCXrpP665vI4Z094h8o7R+5E6yNajZa0UubqjpZFoGq
|
||||
u785/vGXj6mdfIzc9boITGusZCSWeMj5ySMZGZkS+VSvf8VQqj+3YdEu4PLZEjBA
|
||||
ivRFpEejggEQMIIBDDAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH
|
||||
AwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFOv5JcKA
|
||||
KGbibQiSMvPC4a3D/zVFMB8GA1UdIwQYMBaAFN7Ro1lkDsGaNqNG7rAQdu+ul5Vm
|
||||
MDYGCCsGAQUFBwEBBCowKDAmBggrBgEFBQcwAoYaaHR0cDovL3N0Zy14Mi5pLmxl
|
||||
bmNyLm9yZy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3N0Zy14Mi5jLmxlbmNy
|
||||
Lm9yZy8wIgYDVR0gBBswGTAIBgZngQwBAgEwDQYLKwYBBAGC3xMBAQEwCgYIKoZI
|
||||
zj0EAwMDaAAwZQIwXcZbdgxcGH9rTErfSTkXfBKKygU0yO7OpbuNeY1id0FZ/hRY
|
||||
N5fdLOGuc+aHfCsMAjEA0P/xwKr6NQ9MN7vrfGAzO397PApdqfM7VdFK18aEu1xm
|
||||
3HMFKzIR8eEPsMx4smMl
|
||||
-----END CERTIFICATE-----
|
10
src/haproxy/Dockerfile
Normal file
10
src/haproxy/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM haproxy:1.9-alpine
|
||||
|
||||
VOLUME [ "/certs" ]
|
||||
|
||||
RUN apk add --update inotify-tools
|
||||
|
||||
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
|
||||
COPY start-haproxy.sh /start-haproxy
|
||||
|
||||
CMD /start-haproxy
|
@ -2,9 +2,9 @@ global
|
||||
tune.ssl.default-dh-param 1024
|
||||
|
||||
defaults
|
||||
timeout connect 5000
|
||||
timeout client 50000
|
||||
timeout server 50000
|
||||
timeout connect 5s
|
||||
timeout client 50s
|
||||
timeout server 50s
|
||||
|
||||
frontend http-in
|
||||
mode http
|
||||
@ -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
|
||||
|
||||
@ -31,6 +34,10 @@ frontend ssl-in
|
||||
tcp-request content accept if { req.ssl_hello_type 1 }
|
||||
|
||||
acl is_ssl req.ssl_ver 2:3.4
|
||||
|
||||
acl host_tunnel req_ssl_sni -i "tunnel.${HAPROXY_HOSTNAME}"
|
||||
use_backend redirect-to-tunnel-in if host_tunnel
|
||||
|
||||
use_backend redirect-to-https-in if is_ssl
|
||||
use_backend vpn-devices if !is_ssl
|
||||
|
||||
@ -39,6 +46,11 @@ backend redirect-to-https-in
|
||||
balance roundrobin
|
||||
server localhost 127.0.0.1:444 send-proxy-v2
|
||||
|
||||
backend redirect-to-tunnel-in
|
||||
mode tcp
|
||||
balance roundrobin
|
||||
server localhost 127.0.0.1:3129
|
||||
|
||||
frontend https-in
|
||||
mode http
|
||||
option forwardfor
|
||||
@ -61,28 +73,35 @@ backend backend_api
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_api_1 api:80 check port 80
|
||||
server balena_api_1 api:80 check port 80
|
||||
|
||||
backend backend_registry
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_registry_1 registry:80 check port 80
|
||||
server balena_registry_1 registry:80 check port 80
|
||||
|
||||
backend backend_vpn
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_vpn_1 vpn:80 check port 80
|
||||
server balena_vpn_1 vpn:80 check port 80
|
||||
|
||||
backend backend_s3
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server balena_s3_1 s3:80 check port 80
|
||||
|
||||
backend cert-provider
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server balena_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
|
||||
server balena_vpn_1 vpn:443 send-proxy-v2 check-send-proxy port 443
|
||||
|
||||
frontend db
|
||||
mode tcp
|
||||
@ -92,7 +111,7 @@ frontend db
|
||||
|
||||
backend backend_db
|
||||
mode tcp
|
||||
server resin_db_1 db:5432 check port 5432
|
||||
server balena_db_1 db:5432 check port 5432
|
||||
|
||||
frontend redis
|
||||
mode tcp
|
||||
@ -102,9 +121,14 @@ frontend redis
|
||||
|
||||
backend backend_redis
|
||||
mode tcp
|
||||
server resin_redis_1 redis:6379 check port 6379
|
||||
server balena_redis_1 redis:6379 check port 6379
|
||||
|
||||
listen vpn-tunnel
|
||||
mode tcp
|
||||
bind *:3128
|
||||
server balena_vpn vpn:3128 check port 3128
|
||||
|
||||
listen vpn-tunnel-tls
|
||||
mode tcp
|
||||
bind *:3129 ssl crt /etc/ssl/private/open-balena.pem
|
||||
server balena_vpn vpn:3128 check port 3128
|
32
src/haproxy/start-haproxy.sh
Executable file
32
src/haproxy/start-haproxy.sh
Executable 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
|
Reference in New Issue
Block a user