mirror of
https://github.com/balena-io/open-balena.git
synced 2025-03-30 23:46:03 +00:00
Initial commit
This commit is contained in:
parent
2dde9c56c4
commit
6e5a2e36e2
5
.gitignore
vendored
5
.gitignore
vendored
@ -0,0 +1,5 @@
|
||||
*.srl
|
||||
.DS_Store
|
||||
.project
|
||||
.vagrant/
|
||||
src/
|
57
README.md
Normal file
57
README.md
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
## Host requirements
|
||||
|
||||
- Docker >= 18.05.0
|
||||
- Docker Compose >= 1.11
|
||||
- OpenSSL >= 1.0.0
|
||||
- Python >= 2.7 or >=3.4
|
||||
|
||||
## Installation
|
||||
|
||||
### Debian/Ubuntu
|
||||
|
||||
Make sure you have the software listed above installed.
|
||||
|
||||
In a terminal, change into the `open-balena` directory and create a new
|
||||
deployment:
|
||||
|
||||
$ ./scripts/start-project
|
||||
|
||||
This will create a new directory, `demo`, and generate appropriate SSL
|
||||
certificates and configuration for the platform. You can configure the
|
||||
deployment name by passing it as the first argument to the `start-project`
|
||||
command. If you wish to run the platform under a specific domain name,
|
||||
you can specify it as the second argument. The default is `openbalena.local`.
|
||||
For example:
|
||||
|
||||
$ ./scripts/start-project mydeployment my.domain.com
|
||||
|
||||
You can create as many deployments as needed and switch between them using:
|
||||
|
||||
$ ./scripts/select-project mydeployment
|
||||
|
||||
Remove all traces of a project by deleting its folder.
|
||||
|
||||
Start the platform with:
|
||||
|
||||
$ ./scripts/run-fig-command up
|
||||
|
||||
Stop the platform with:
|
||||
|
||||
$ ./scripts/run-fig-command stop
|
||||
|
||||
### macOS & Windows
|
||||
|
||||
On macOS and Windows you need Vagrant. `open-balena` is not being tested with
|
||||
docker-machine. `open-balena` comes with an appropriate `Vagrantfile` for
|
||||
setting up the VM, installing dependencies and starting the platform.
|
||||
|
||||
- Install Vagrant >= 2.0
|
||||
- `$ vagrant plugin install vagrant-docker-compose`
|
||||
- `$ vagrant up`
|
||||
|
||||
When provisioning completes and the VM has started, `open-balena` services
|
||||
should be running inside the VM. You will need to expose these services to
|
||||
the outside in order for them to be reachable by devices. To do so, you must
|
||||
setup DNS for the domain name you've deployed the instance as to point to the
|
||||
VM's IP address.
|
30
Vagrantfile
vendored
Normal file
30
Vagrantfile
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
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.configure('2') do |config|
|
||||
config.vm.define 'open-balena-vm'
|
||||
config.vm.box = 'bento/ubuntu-16.04'
|
||||
config.vm.box_url = 'https://vagrantcloud.com/bento/boxes/ubuntu-16.04/versions/201803.24.0/providers/virtualbox.box'
|
||||
|
||||
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', true)
|
||||
|
||||
config.ssh.forward_agent = true
|
||||
|
||||
config.vm.provision :docker
|
||||
config.vm.provision :docker_compose
|
||||
|
||||
# FIXME: remove node
|
||||
config.vm.provision :shell, inline: 'apt-get install nodejs'
|
||||
|
||||
# FIXME: remove `docker login`
|
||||
config.vm.provision :shell, inline: "docker login --username resindev --password #{ENV.fetch('DOCKERHUB_PASSWORD')}"
|
||||
config.vm.provision :shell, inline: '/home/vagrant/open-balena/scripts/start-project'
|
||||
config.vm.provision :shell, inline: '/home/vagrant/open-balena/scripts/run-fig-command up -d', run: 'always'
|
||||
end
|
15
compose/common.yml
Normal file
15
compose/common.yml
Normal file
@ -0,0 +1,15 @@
|
||||
version: '2.1'
|
||||
|
||||
services:
|
||||
component:
|
||||
cap_add:
|
||||
- SYS_ADMIN
|
||||
- SYS_RESOURCE
|
||||
environment:
|
||||
- CONFD_BACKEND=ENV
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
|
||||
system:
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
217
compose/services.yml
Normal file
217
compose/services.yml
Normal file
@ -0,0 +1,217 @@
|
||||
version: '2.1'
|
||||
|
||||
volumes:
|
||||
db:
|
||||
registry:
|
||||
# FIXME: remove
|
||||
img:
|
||||
|
||||
services:
|
||||
api:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: resin/resin-api:${OPENBALENA_API_VERSION_TAG:-master}
|
||||
depends_on:
|
||||
- db
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
environment:
|
||||
ADMIN_LIST:
|
||||
AUTH_RESINOS_REGISTRY_CODE: ${OPENBALENA_RESINOS_REGISTRY_CODE}
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
DB_HOST: db
|
||||
DB_PASSWORD: docker
|
||||
DB_PORT: 5432
|
||||
DB_USER: docker
|
||||
DEBUG: '${OPENBALENA_DEBUG}'
|
||||
DEVICE_CONFIG_OPENVPN_CA: yyy
|
||||
DEVICE_CONFIG_OPENVPN_CONFIG: yyy
|
||||
DEVICE_CONFIG_SSH_AUTHORIZED_KEYS: yyy
|
||||
EMAIL_RECIPIENT_OVERRIDE:
|
||||
HOST: ${OPENBALENA_HOST_NAME}
|
||||
IMAGE_MAKER_URL: img.${OPENBALENA_HOST_NAME}
|
||||
JSON_WEB_TOKEN_EXPIRY_MINUTES: 10080
|
||||
JSON_WEB_TOKEN_SECRET: ${OPENBALENA_JWT_SECRET}
|
||||
PRODUCTION_MODE: '${OPENBALENA_PRODUCTION_MODE}'
|
||||
REGISTRY2_HOST: registry.${OPENBALENA_HOST_NAME}
|
||||
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'
|
||||
VPN_HOST: vpn.${OPENBALENA_HOST_NAME}
|
||||
VPN_PORT: 443
|
||||
VPN_SERVICE_API_KEY: ${OPENBALENA_VPN_SERVICE_API_KEY}
|
||||
# FIXME: remove all the following
|
||||
ADMIN_HOST: __unused__
|
||||
AUTH_FACEBOOK_CLIENT_ID: __unused__
|
||||
AUTH_FACEBOOK_CLIENT_SECRET: __unused__
|
||||
AUTH_GITHUB_CLIENT_ID: __unused__
|
||||
AUTH_GITHUB_CLIENT_SECRET: __unused__
|
||||
AUTH_GOOGLE_CLIENT_ID: __unused__
|
||||
AUTH_GOOGLE_CLIENT_SECRET: __unused__
|
||||
AUTH_TWITTER_CONSUMER_KEY: __unused__
|
||||
AUTH_TWITTER_CONSUMER_SECRET: __unused__
|
||||
BUILDER_SERVICE_API_KEY: __unused__1 # must be unique
|
||||
COOKIE_SESSION_SECRET: __unused__
|
||||
DB_ANALYTICS_PASSWORD:
|
||||
DELTA_HOST: __unused__
|
||||
DELTA_SERVICE_API_KEY: __unused__2 # must be unique
|
||||
DEVICE_URLS_BASE: __unused__
|
||||
DIGITIZER_API_KEY: __unused__3 # must be unique
|
||||
GA_ID: __unused__
|
||||
GA_SITE: __unused__
|
||||
GEOIP_LICENCE_KEY: __unused__
|
||||
GEOIP_USER_ID: __unused__
|
||||
GIT_HOST: __unused__
|
||||
GIT_HOSTNAME: __unused__
|
||||
GIT_PORT: 80
|
||||
GIT_SERVICE_API_KEY: __unused__4 # must be unique
|
||||
INTERCOM_APP_ID: __unused__
|
||||
INTERCOM_SECRET_KEY: __unused__
|
||||
MAILGUN_API_KEY: __unused__
|
||||
MAILGUN_DOMAIN: __unused__
|
||||
MIXPANEL_ACCOUNT_ID: __unused__
|
||||
MIXPANEL_API_KEY: __unused__
|
||||
MIXPANEL_API_SECRET: __unused__
|
||||
MIXPANEL_TOKEN: __unused__
|
||||
PROXY_SERVICE_API_KEY: __unused__5 # must be unique
|
||||
PUBNUB_PUBLISH_KEY: __unused__
|
||||
PUBNUB_SUBSCRIBE_KEY: __unused__
|
||||
RECAPTCHA_PRIVATE_KEY: __unused__
|
||||
RECAPTCHA_PUBLIC_KEY: __unused__
|
||||
RECURLY_PRIVATE_KEY: __unused__
|
||||
RECURLY_PUBLIC_KEY: __unused__
|
||||
RECURLY_SUBDOMAIN: __unused__
|
||||
REDIS_HOST: __unused__
|
||||
REDIS_PORT: 6379
|
||||
REGISTRY_HOST: __unused__
|
||||
SENTRY_DSN:
|
||||
TOKEN_AUTH_BUILDER_TOKEN: __unused__
|
||||
TWOFACTOR_ISSUER: __unused__
|
||||
UI_HOST: __unused__
|
||||
ZENDESK_DOMAIN: __unused__
|
||||
ZENDESK_SHARED_SECRET: __unused__
|
||||
|
||||
registry:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: resin/open-balena-registry:${OPENBALENA_REGISTRY_VERSION_TAG:-master}
|
||||
depends_on:
|
||||
- api
|
||||
volumes:
|
||||
- registry:/data
|
||||
environment:
|
||||
API_TOKENAUTH_CRT: ${OPENBALENA_TOKEN_AUTH_PUB}
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
COMMON_REGION:
|
||||
REGISTRY2_HOST: registry.${OPENBALENA_HOST_NAME}
|
||||
REGISTRY2_S3_BUCKET:
|
||||
REGISTRY2_S3_KEY:
|
||||
REGISTRY2_S3_SECRET:
|
||||
REGISTRY2_STORAGEPATH: /data
|
||||
TOKENAUTH_ISSUER: api.${OPENBALENA_HOST_NAME}
|
||||
TOKENAUTH_REALM: https://api.${OPENBALENA_HOST_NAME}/auth/v1/token
|
||||
# FIXME: remove the following
|
||||
REGISTRY2_SECRETKEY: __unused__
|
||||
|
||||
vpn:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: resin/resin-vpn:${OPENBALENA_VPN_VERSION_TAG:-master}
|
||||
depends_on:
|
||||
- api
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
environment:
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
BALENA_VPN_PORT: 443
|
||||
LOGENTRIES_TOKEN:
|
||||
PRODUCTION_MODE: '${OPENBALENA_PRODUCTION_MODE}'
|
||||
RESIN_API_HOST: api.${OPENBALENA_HOST_NAME}
|
||||
RESIN_VPN_GATEWAY: 10.2.0.1
|
||||
SENTRY_DSN:
|
||||
VPN_HAPROXY_USEPROXYPROTOCOL: 'true'
|
||||
VPN_SERVICE_API_KEY: ${OPENBALENA_VPN_SERVICE_API_KEY}
|
||||
# FIXME: remove all of the following
|
||||
API_SERVICE_API_KEY: __unused__
|
||||
PROXY_SERVICE_API_KEY: __unused__5
|
||||
|
||||
db:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: system
|
||||
image: resin/open-balena-db:${OPENBALENA_DB_VERSION_TAG:-master}
|
||||
volumes:
|
||||
- db:/var/lib/postgresql/data
|
||||
|
||||
haproxy:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: system
|
||||
build: ../haproxy
|
||||
depends_on:
|
||||
- api
|
||||
- registry
|
||||
- vpn
|
||||
- db
|
||||
# FIXME: remove
|
||||
- proxy
|
||||
- img
|
||||
ports:
|
||||
- "80:80"
|
||||
- "222:222"
|
||||
- "443:443"
|
||||
- "5432:5432"
|
||||
environment:
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
HAPROXY_HOSTNAME: ${OPENBALENA_HOST_NAME}
|
||||
|
||||
# FIXME: remove the following
|
||||
|
||||
proxy:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: resin/resin-proxy:${OPENBALENA_PROXY_VERSION_TAG:-master}
|
||||
depends_on:
|
||||
- api
|
||||
- vpn
|
||||
environment:
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
DEBUG: '${OPENBALENA_DEBUG}'
|
||||
DEVICE_URLS_BASE: devices.${OPENBALENA_HOST_NAME}
|
||||
IDLE_CONNECTION_TIMEOUT: 50
|
||||
JSON_WEB_TOKEN_SECRET: ${OPENBALENA_JWT_SECRET}
|
||||
LOGENTRIES_TOKEN:
|
||||
PRODUCTION_MODE: '${OPENBALENA_PRODUCTION_MODE}'
|
||||
PROXY_PROTOCOL_PORTS:
|
||||
PROXY_SERVICE_API_KEY: __unused__5
|
||||
RESIN_API_HOST: api.${OPENBALENA_HOST_NAME}
|
||||
SENTRY_DSN:
|
||||
|
||||
img:
|
||||
extends:
|
||||
file: ./common.yml
|
||||
service: component
|
||||
image: resin/resin-img:${OPENBALENA_IMG_VERSION_TAG:-master}
|
||||
depends_on:
|
||||
- api
|
||||
volumes:
|
||||
- img:/prepdir
|
||||
environment:
|
||||
BALENA_ROOT_CA: ${OPENBALENA_ROOT_CA}
|
||||
DEVELOPMENT: 1
|
||||
LKL_MEMORY: 268435456
|
||||
LOGENTRIES_TOKEN:
|
||||
NODEPING_KEY: xxx
|
||||
RESIN_IMG_S3_ACCESS_KEY: abcdef1234
|
||||
RESIN_IMG_S3_BUCKET: resin-image-maker
|
||||
RESIN_IMG_S3_ENDPOINT: s3.${OPENBALENA_HOST_NAME}
|
||||
RESIN_IMG_S3_FORCE_PATH_STYLE: 'true'
|
||||
RESIN_IMG_S3_SECRET_KEY: 1234567890
|
||||
RESIN_IMG_STORAGE_DRIVER: passthrough
|
||||
SENTRY_DSN:
|
6
haproxy/Dockerfile
Normal file
6
haproxy/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
FROM haproxy:1.8-alpine
|
||||
|
||||
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
|
||||
COPY entry.sh /open-balena-entry
|
||||
|
||||
CMD /open-balena-entry
|
9
haproxy/entry.sh
Executable file
9
haproxy/entry.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
CA_B64="$BALENA_ROOT_CA"
|
||||
CA_FILE=/etc/ssl/private/root.chain.pem
|
||||
|
||||
mkdir -p $(dirname "$CA_FILE")
|
||||
echo "$CA_B64" | base64 -d >"$CA_FILE"
|
||||
|
||||
exec haproxy -f /usr/local/etc/haproxy/haproxy.cfg
|
123
haproxy/haproxy.cfg
Normal file
123
haproxy/haproxy.cfg
Normal file
@ -0,0 +1,123 @@
|
||||
global
|
||||
tune.ssl.default-dh-param 1024
|
||||
|
||||
defaults
|
||||
timeout connect 5000
|
||||
timeout client 50000
|
||||
timeout server 50000
|
||||
|
||||
frontend http-in
|
||||
mode http
|
||||
option forwardfor
|
||||
bind *:80
|
||||
reqadd X-Forwarded-Proto:\ http
|
||||
|
||||
acl host_api hdr_dom(host) -i "api.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_api if host_api
|
||||
|
||||
acl host_registry hdr_dom(host) -i "registry.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_registry if host_registry
|
||||
|
||||
acl host_vpn hdr_dom(host) -i "vpn.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_vpn if host_vpn
|
||||
|
||||
# FIXME: remove
|
||||
acl host_proxy hdr_dom(host) -i "devices.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_proxy if host_proxy
|
||||
|
||||
# FIXME: remove
|
||||
acl host_img hdr_dom(host) -i "img.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_img if host_img
|
||||
|
||||
frontend ssl-in
|
||||
mode tcp
|
||||
bind *:443
|
||||
tcp-request inspect-delay 2s
|
||||
tcp-request content accept if { req.ssl_hello_type 1 }
|
||||
|
||||
acl is_ssl req.ssl_ver 2:3.4
|
||||
use_backend redirect-to-https-in if is_ssl
|
||||
use_backend vpn-devices if !is_ssl
|
||||
|
||||
backend redirect-to-https-in
|
||||
mode tcp
|
||||
balance roundrobin
|
||||
server localhost 127.0.0.1:444 send-proxy-v2
|
||||
|
||||
frontend https-in
|
||||
mode http
|
||||
option forwardfor
|
||||
bind 127.0.0.1:444 ssl crt /etc/ssl/private/root.chain.pem accept-proxy
|
||||
reqadd X-Forwarded-Proto:\ https
|
||||
|
||||
acl host_api hdr_dom(host) -i "api.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_api if host_api
|
||||
|
||||
acl host_registry hdr_dom(host) -i "registry.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_registry if host_registry
|
||||
|
||||
# FIXME: remove
|
||||
acl host_proxy hdr_dom(host) -i "devices.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_proxy if host_proxy
|
||||
|
||||
# FIXME: remove
|
||||
acl host_img hdr_dom(host) -i "img.${HAPROXY_HOSTNAME}"
|
||||
use_backend backend_img if host_img
|
||||
|
||||
backend backend_api
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_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
|
||||
|
||||
backend backend_vpn
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_vpn_1 vpn:80 check port 80
|
||||
|
||||
# FIXME: remove
|
||||
backend backend_proxy
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_proxy_1 proxy:80 send-proxy check-send-proxy port 80
|
||||
|
||||
# FIXME: remove
|
||||
backend backend_img
|
||||
mode http
|
||||
option forwardfor
|
||||
balance roundrobin
|
||||
server resin_img_1 img:80 check port 80
|
||||
|
||||
# FIXME: remove
|
||||
frontend devices-ssh-gateway
|
||||
mode tcp
|
||||
bind *:222
|
||||
default_backend devices-ssh-gateway
|
||||
timeout client 1h
|
||||
|
||||
# FIXME: remove
|
||||
backend devices-ssh-gateway
|
||||
mode tcp
|
||||
server resin_proxy_1 proxy:2222 check port 2222
|
||||
|
||||
backend vpn-devices
|
||||
mode tcp
|
||||
server resin_vpn_1 vpn:443 send-proxy-v2 check-send-proxy port 443
|
||||
|
||||
frontend db
|
||||
mode tcp
|
||||
bind *:5432
|
||||
default_backend db
|
||||
timeout client 1h
|
||||
|
||||
backend db
|
||||
mode tcp
|
||||
server resin_db_1 db:5432 check port 5432
|
79
scripts/_keyid.js
Normal file
79
scripts/_keyid.js
Normal file
@ -0,0 +1,79 @@
|
||||
'use strict';
|
||||
|
||||
var crypto = require('crypto');
|
||||
var fs = require('fs');
|
||||
|
||||
var base32 = (function() {
|
||||
// Extracted from https://github.com/chrisumbel/thirty-two
|
||||
// to avoid having to install packages for this script.
|
||||
var charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
var byteTable = [
|
||||
0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
];
|
||||
|
||||
function quintetCount(buff) {
|
||||
var quintets = Math.floor(buff.length / 5);
|
||||
return buff.length % 5 == 0 ? quintets: quintets + 1;
|
||||
}
|
||||
|
||||
return function(plain) {
|
||||
if (!Buffer.isBuffer(plain)) {
|
||||
plain = new Buffer(plain);
|
||||
}
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var shiftIndex = 0;
|
||||
var digit = 0;
|
||||
var encoded = new Buffer(quintetCount(plain) * 8);
|
||||
|
||||
/* byte by byte isn't as pretty as quintet by quintet but tests a bit
|
||||
faster. will have to revisit. */
|
||||
while(i < plain.length) {
|
||||
var current = plain[i];
|
||||
|
||||
if(shiftIndex > 3) {
|
||||
digit = current & (0xff >> shiftIndex);
|
||||
shiftIndex = (shiftIndex + 5) % 8;
|
||||
digit = (digit << shiftIndex) | ((i + 1 < plain.length) ?
|
||||
plain[i + 1] : 0) >> (8 - shiftIndex);
|
||||
i++;
|
||||
} else {
|
||||
digit = (current >> (8 - (shiftIndex + 5))) & 0x1f;
|
||||
shiftIndex = (shiftIndex + 5) % 8;
|
||||
if(shiftIndex == 0) i++;
|
||||
}
|
||||
|
||||
encoded[j] = charTable.charCodeAt(digit);
|
||||
j++;
|
||||
}
|
||||
|
||||
for (i = j; i < encoded.length; i++) {
|
||||
encoded[i] = 0x3d; //'='.charCodeAt(0)
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
})();
|
||||
|
||||
function joseKeyId(der) {
|
||||
var hasher = crypto.createHash('sha256');
|
||||
hasher.update(der);
|
||||
var b32 = base32(hasher.digest().slice(0, 30)).toString('ascii');
|
||||
var chunks = [];
|
||||
for (var i = 0; i < b32.length; i += 4) {
|
||||
chunks.push(b32.substr(i, 4));
|
||||
}
|
||||
return chunks.join(':');
|
||||
}
|
||||
|
||||
var derFilePath = process.argv[2];
|
||||
var der = fs.readFileSync(derFilePath);
|
||||
process.stdout.write(joseKeyId(der));
|
55
scripts/gen-root-ca-cert
Executable file
55
scripts/gen-root-ca-cert
Executable file
@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CN=$1
|
||||
OUT=${2:-.}
|
||||
|
||||
CA="${CN}-ca"
|
||||
CA_FILE="${OUT}/ca"
|
||||
CN_FILE="${OUT}/root"
|
||||
|
||||
CN_EXPIRY_DAYS=730
|
||||
CA_EXPIRY_DAYS=3650
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 HOST_NAME [OUT]"
|
||||
echo
|
||||
echo " HOST_NAME the domain name the certificate is valid for, eg. example.com"
|
||||
echo " OUT path to output directory generated files will be placed in"
|
||||
echo
|
||||
}
|
||||
|
||||
if [ -z "$CN" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat > "${CN_FILE}.v3.ext" <<STR
|
||||
authorityKeyIdentifier = keyid,issuer
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = *.${CN}
|
||||
STR
|
||||
|
||||
# Create a secret key and CA file for the self-signed CA
|
||||
openssl genrsa -out "${CA_FILE}.key" 2048 2>/dev/null
|
||||
openssl req -x509 -new -nodes -sha256 -days $CA_EXPIRY_DAYS -key "${CA_FILE}.key" -subj "/CN=${CA}" -out "${CA_FILE}.pem" 2>/dev/null
|
||||
|
||||
# Create a secret key and Certificate Signing Request (CSR) for the domain
|
||||
openssl genrsa -out "${CN_FILE}.key" 2048 2>/dev/null
|
||||
openssl req -new -key "${CN_FILE}.key" -subj "/CN=${CN}" -out "${CN_FILE}.csr" 2>/dev/null
|
||||
|
||||
# Sign the request with the self-signed CA and extension file
|
||||
openssl x509 -req -sha256 -days $CN_EXPIRY_DAYS -in "${CN_FILE}.csr" -CA "${CA_FILE}.pem" -CAkey "${CA_FILE}.key" -CAcreateserial -out "${CN_FILE}.pem" -extfile "${CN_FILE}.v3.ext" 2>/dev/null
|
||||
|
||||
# Create the custom certificate chain file
|
||||
cat "${CN_FILE}.pem" "${CA_FILE}.pem" "${CN_FILE}.key" >"${CN_FILE}.chain.pem"
|
||||
|
||||
# Cleanup
|
||||
rm "${CA_FILE}.key" "${CA_FILE}.pem" "${CN_FILE}.key" "${CN_FILE}.pem" "${CN_FILE}.csr" "${CN_FILE}.v3.ext"
|
||||
|
||||
echo "ROOT_CA=${CN_FILE}.chain.pem"
|
42
scripts/gen-token-auth-cert
Executable file
42
scripts/gen-token-auth-cert
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CMD=$0
|
||||
DIR=$(dirname "$CMD")
|
||||
|
||||
CN=$1
|
||||
OUT=${2:-.}
|
||||
|
||||
CERT_FILE="${OUT}/token-auth"
|
||||
EXPIRY_DAYS=730
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 HOST_NAME [OUT]"
|
||||
echo
|
||||
echo " HOST_NAME the domain name the certificate is valid for, eg. example.com"
|
||||
echo " OUT path to output directory generated files will be placed in"
|
||||
echo
|
||||
}
|
||||
|
||||
keyid() {
|
||||
# FIXME: do this in bash or python, not node
|
||||
nodejs "${DIR}/_keyid.js" "$1"
|
||||
}
|
||||
|
||||
if [ -z "$CN" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
openssl ecparam -name prime256v1 -genkey -noout -out "${CERT_FILE}.pem" 2>/dev/null
|
||||
openssl req -x509 -new -nodes -days "${EXPIRY_DAYS}" -key "${CERT_FILE}.pem" -subj "/CN=api.${CN}" -out "${CERT_FILE}.crt" 2>/dev/null
|
||||
openssl ec -in "${CERT_FILE}.pem" -pubout -outform DER -out "${CERT_FILE}".der 2>/dev/null
|
||||
keyid "${CERT_FILE}".der >"${CERT_FILE}".kid
|
||||
|
||||
# Cleanup
|
||||
rm "${CERT_FILE}.der"
|
||||
|
||||
echo "PUB=${CERT_FILE}.crt"
|
||||
echo "KEY=${CERT_FILE}.pem"
|
||||
echo "KID=${CERT_FILE}.kid"
|
40
scripts/make-env
Executable file
40
scripts/make-env
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
HOST_NAME="$1"
|
||||
ROOT_CA="$2"
|
||||
TOKEN_AUTH_PUB="$3"
|
||||
TOKEN_AUTH_KEY="$4"
|
||||
TOKEN_AUTH_KID="$5"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 HOST_NAME ROOT_CA TOKEN_AUTH_PUB TOKEN_AUTH_KEY TOKEN_AUTH_KID"
|
||||
echo
|
||||
}
|
||||
|
||||
randstr() {
|
||||
LC_CTYPE=C tr -dc A-Za-z0-9 < /dev/urandom | fold -w ${1:-32} | head -n 1
|
||||
}
|
||||
|
||||
b64encode() {
|
||||
cat "$1" | base64 --wrap=0 2>/dev/null || cat "$1" | base64 --break=0
|
||||
}
|
||||
|
||||
if [ -z "$HOST_NAME" ] || [ -z "$ROOT_CA" ] || [ -z "$TOKEN_AUTH_PUB" ] || [ -z "$TOKEN_AUTH_KEY" ] || [ -z "$TOKEN_AUTH_KID" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<STR
|
||||
export OPENBALENA_DEBUG=true
|
||||
export OPENBALENA_PRODUCTION_MODE=false
|
||||
export OPENBALENA_HOST_NAME=$HOST_NAME
|
||||
export OPENBALENA_JWT_SECRET=$(randstr 32)
|
||||
export OPENBALENA_RESINOS_REGISTRY_CODE=$(randstr 32)
|
||||
export OPENBALENA_ROOT_CA=$(b64encode "$ROOT_CA")
|
||||
export OPENBALENA_TOKEN_AUTH_PUB=$(b64encode "$TOKEN_AUTH_PUB")
|
||||
export OPENBALENA_TOKEN_AUTH_KEY=$(b64encode "$TOKEN_AUTH_KEY")
|
||||
export OPENBALENA_TOKEN_AUTH_KID=$(b64encode "$TOKEN_AUTH_KID")
|
||||
export OPENBALENA_VPN_SERVICE_API_KEY=$(randstr 32)
|
||||
STR
|
36
scripts/patch-hosts
Executable file
36
scripts/patch-hosts
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CMD=$0
|
||||
DIR=$(dirname "$CMD")
|
||||
|
||||
HOST_NAME=$1
|
||||
|
||||
SERVICES="api registry vpn db"
|
||||
SERVICES="${SERVICES} img devices" # FIXME: remove
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 HOST_NAME"
|
||||
echo
|
||||
echo " HOST_NAME the domain name to add host entries for, eg. example.com"
|
||||
echo
|
||||
}
|
||||
|
||||
if [ -z "$HOST_NAME" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We need sudo to write to /etc/hosts, so first write to a temp file and then
|
||||
# append all entries to hosts file.
|
||||
tmp=$(mktemp --tmpdir openbalena.XXXX)
|
||||
for service in $SERVICES; do
|
||||
name="${service}.${HOST_NAME}"
|
||||
if ! grep "\s$name" /etc/hosts >/dev/null 2>&1 ; then
|
||||
echo "adding $name"
|
||||
echo "127.0.0.1 $name" >>$tmp
|
||||
fi
|
||||
done
|
||||
cat $tmp | sudo tee -a /etc/hosts >/dev/null
|
||||
rm -f $tmp
|
31
scripts/run-fig-command
Executable file
31
scripts/run-fig-command
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CMD=$0
|
||||
DIR=$(dirname "$CMD")
|
||||
BASE_DIR=$(dirname "$DIR")
|
||||
|
||||
echo_bold() {
|
||||
printf "\033[1m${@}\033[0m\n"
|
||||
}
|
||||
|
||||
PROJECT_FILE="${BASE_DIR}/.project"
|
||||
if [ ! -f "$PROJECT_FILE" ]; then
|
||||
echo_bold 'No project activated. Please create or select an existing one first.'
|
||||
echo_bold 'See README.md for help.'
|
||||
exit 1
|
||||
fi
|
||||
PROJECT=$(cat "$PROJECT_FILE")
|
||||
if [ ! -f "${PROJECT}/activate" ]; then
|
||||
echo_bold 'No project activated. Please create or select an existing one first.'
|
||||
echo_bold 'See README.md for help.'
|
||||
exit 1
|
||||
fi
|
||||
PROJECT_NAME=$(basename "$PROJECT")
|
||||
|
||||
. "${PROJECT}/activate"; docker-compose \
|
||||
--project-name $PROJECT_NAME \
|
||||
-f "${BASE_DIR}/compose/services.yml" \
|
||||
-f "${PROJECT}/docker-compose.yml" \
|
||||
"$@"
|
34
scripts/select-project
Executable file
34
scripts/select-project
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CMD=$0
|
||||
DIR=$(dirname "$CMD")
|
||||
BASE_DIR=$(dirname "$DIR")
|
||||
PROJECT_PATH="$1"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 PROJECT_PATH"
|
||||
echo
|
||||
echo " PROJECT_PATH path to the project; can be relative to open-balena root."
|
||||
echo
|
||||
}
|
||||
|
||||
if [ -z "$PROJECT_PATH" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROJECT_DIR=$(realpath "$PROJECT_PATH")
|
||||
|
||||
if [ ! -d "$PROJECT_DIR" ]; then
|
||||
echo 'Project path refers to a directory that does not exist.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${PROJECT_DIR}/activate" ]; then
|
||||
echo 'Project path refers to a directory that is not a valid porject.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -n $PROJECT_DIR >"${BASE_DIR}/.project"
|
58
scripts/start-project
Executable file
58
scripts/start-project
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
CMD=$0
|
||||
DIR=$(dirname "$CMD")
|
||||
|
||||
HOST_NAME=${1:-openbalena.local}
|
||||
PROJECT_NAME=${2:-demo}
|
||||
|
||||
PROJECT_DIR="$(pwd)/${PROJECT_NAME}"
|
||||
CERTS_DIR="${PROJECT_DIR}/certs"
|
||||
|
||||
usage() {
|
||||
echo "usage: $0 [HOST_NAME [PROJECT_NAME]]"
|
||||
echo
|
||||
echo " HOST_NAME the domain name this deployment will run as, eg. example.com. Default is 'openbalena.local'"
|
||||
echo " PROJECT_NAME a name for the deployment, eg. staging. Default is 'demo'"
|
||||
echo
|
||||
}
|
||||
|
||||
echo_bold() {
|
||||
printf "\033[1m${@}\033[0m\n"
|
||||
}
|
||||
|
||||
if [ -d "$PROJECT_DIR" ]; then
|
||||
echo 'Project directory already exists. Please remove it or specify another project name.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo_bold "==> Creating new project at: $PROJECT_DIR"
|
||||
mkdir -p "$PROJECT_DIR" "$CERTS_DIR"
|
||||
|
||||
echo_bold "==> Creating root CA cert..."
|
||||
"${DIR}/gen-root-ca-cert" $HOST_NAME "$CERTS_DIR"
|
||||
|
||||
echo_bold "==> Creating token auth cert..."
|
||||
"${DIR}/gen-token-auth-cert" $HOST_NAME "$CERTS_DIR"
|
||||
|
||||
echo_bold "==> Setting up environment..."
|
||||
cat >"${PROJECT_DIR}/activate" <<STR
|
||||
$("${DIR}/make-env" \
|
||||
$HOST_NAME \
|
||||
"${CERTS_DIR}/root.chain.pem" \
|
||||
"${CERTS_DIR}/token-auth.crt" \
|
||||
"${CERTS_DIR}/token-auth.pem" \
|
||||
"${CERTS_DIR}/token-auth.kid")
|
||||
STR
|
||||
|
||||
echo_bold "==> Adding default compose file..."
|
||||
echo "version: '2.1'" >"${PROJECT_DIR}/docker-compose.yml"
|
||||
|
||||
# FIXME: should be explicitly requested via a flag
|
||||
echo_bold "==> Patching /etc/hosts..."
|
||||
"${DIR}/patch-hosts" $HOST_NAME
|
||||
|
||||
echo_bold "==> Activating project..."
|
||||
"${DIR}/select-project" "$PROJECT_DIR"
|
1
src/README
Normal file
1
src/README
Normal file
@ -0,0 +1 @@
|
||||
This is the working folder for any specific container you might want to work on.
|
Loading…
x
Reference in New Issue
Block a user