From 047793a495d9d7740f80330ccf387974aff1855f Mon Sep 17 00:00:00 2001 From: Krispin Date: Wed, 4 Oct 2023 09:40:42 +0200 Subject: [PATCH] add ansible and local setup --- .gitignore | 2 + Makefile | 54 ++++ README.md | 23 ++ adapters/actor.py | 179 +++++++++++++ ansible/deploy.yaml | 0 ansible/environments/prod/default.env | 0 .../prod/group_vars/all/001_env_specific.yaml | 5 + ansible/environments/prod/hosts.yaml | 6 + ansible/environments/prod/secrets.yaml | 6 + ansible/requirements.yaml | 5 + ansible/roles/common/tasks/main.yml | 7 + ansible/setup.yaml | 7 + config/bffh/bffh.dhall | 237 ++++++++++++++++++ config/bffh/users.toml | 173 +++++++++++++ config/cert/cert.pem | 31 +++ config/cert/key.pem | 52 ++++ config/mosquitto/mosquitto.conf | 3 + docker-compose.yaml | 28 +++ 18 files changed, 818 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 adapters/actor.py create mode 100644 ansible/deploy.yaml create mode 100644 ansible/environments/prod/default.env create mode 100644 ansible/environments/prod/group_vars/all/001_env_specific.yaml create mode 100644 ansible/environments/prod/hosts.yaml create mode 100644 ansible/environments/prod/secrets.yaml create mode 100644 ansible/requirements.yaml create mode 100644 ansible/roles/common/tasks/main.yml create mode 100644 ansible/setup.yaml create mode 100644 config/bffh/bffh.dhall create mode 100644 config/bffh/users.toml create mode 100644 config/cert/cert.pem create mode 100644 config/cert/key.pem create mode 100644 config/mosquitto/mosquitto.conf create mode 100644 docker-compose.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c842e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.DS_Store \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1ad7553 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +.PHONY: help + +ENVIRONMENT ?= prod +# Include only if file exists: +-include ./ansible/environments/${ENVIRONMENT}/default.env +-include .env + +.EXPORT_ALL_VARIABLES: +PROJECT ?= fabaccess-cb +# ansible playbook flags: +TAGS ?= "" +LIMIT ?= "" + +help: ## Show help for this Makefile + @grep -Eh '^[a-zA-Z_-]+:.*?## .*$$' ${MAKEFILE_LIST} | sort | awk 'BEGIN {FS = ":.*? ##"}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +# Generate local config. +# Executed only when starting `make up` the first time: +.env: + cp ./ansible/environments/${ENVIRONMENT}/default.env .env + +up: .env ## Start local dev environment with docker-compose + @docker-compose -p "${PROJECT}" up --force-recreate + +ansible-requirements: ## Install ansible requirements via ansible-galaxy. + ansible-galaxy collection install -r ./ansible/requirements.yaml + ansible-galaxy role install -r ./ansible/requirements.yaml + +ansible-facts: ## Show facts for a host; e.g. make ansible-facts -e HOST=oklab + ansible -i ./ansible/environments/${ENVIRONMENT} ${HOST} -m setup + +setup: ## Setup fabaccess hosts with ansible; e.g. make setup -e TAGS=common + ansible-playbook \ + -vv \ + --vault-id "${ENVIRONMENT}@prompt" \ + -e "@./ansible/environments/${ENVIRONMENT}/secrets.yaml" \ + -i "./ansible/environments/${ENVIRONMENT}" \ + --tags "${TAGS}" \ + --limit "${LIMIT}" \ + ansible/setup.yaml + +deploy: ## Deploy fabaccess with ansible. + ansible-playbook \ + -vv \ + --vault-id "${ENVIRONMENT}@prompt" \ + -e "@./ansible/environments/${ENVIRONMENT}/secrets.yaml" \ + -i "./ansible/environments/${ENVIRONMENT}" \ + ansible/deploy.yaml + +secrets-encrypt: ## Encrypt secrets with ansible-vault + ansible-vault encrypt --vault-id "${ENVIRONMENT}@prompt" "./ansible/environments/${ENVIRONMENT}/secrets.yaml" + +secrets-decrypt: ## Decrypt secrets with ansible-vault + ansible-vault decrypt --vault-id "${ENVIRONMENT}@prompt" "./ansible/environments/${ENVIRONMENT}/secrets.yaml" \ No newline at end of file diff --git a/README.md b/README.md index 8660c94..318ae8a 100644 --- a/README.md +++ b/README.md @@ -1 +1,24 @@ # fabaccess-cb + + +### Decrypt secrets + +When you add a new secret to the `secrets.yaml` +you have to decrypt the file first: +```bash +make secrets-decrypt -e ENVIRONMENT=prod +``` + +### Encrypt secrets + +Before you commit any changes to the git repo +you have to encrypt the `secrets.yaml` first: +```bash +make secrets-encrypt -e ENVIRONMENT=prod +``` + +### Setup host + +```bash +make setup -e TAGS=common +``` \ No newline at end of file diff --git a/adapters/actor.py b/adapters/actor.py new file mode 100644 index 0000000..489260c --- /dev/null +++ b/adapters/actor.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 + +import sys +import argparse + +def on_free(args, actor_name): + """ + Function called when the state of the connected machine changes to Free + again + """ + if args.verbose > 2: + print("on_free called!") + + if actor_name == "DoorControl1": + # Do whatever you want to do in case `DoorControl1` is returned back to free. + # Keep in mind that process actors should return quickly to not miss + # updates, so if you need to do things that take a while fork a new + # process e.g. with the `subprocess` Module + print("I'm locking door 1!") + pass + elif actor_name == "DoorControl2": + print("I'm locking door 2!") + pass # Close a different door + else: + if not args.quiet: + print("process called with unknown id %s for state `Free`" % actor_name) + # It's a good idea to exit with an error code in case something + # unexpected happens. + # The process module logs everything printed to stdout by actors into + # the server log, but marks them as `Error` in case the actor process + # exits with a code != 0, making debugging somewhat easier. + exit(-1) + +def on_use(args, actor_name, user_id): + """ + Function called when an user takes control of the connected machine + + user_id contains the UID of the user now using the machine + """ + if args.verbose > 2: + print("on_use called!") + if actor_name == "DoorControl1": + print("I'm opening door 1 for 10 seconds!") + pass # Open door one + elif actor_name == "DoorControl2": + print("I'm opening door 2 for 10 seconds!") + pass # Open a different door + else: + if not args.quiet: + print("process called with unknown id %s for state `InUse`" % actor_name) + # It's a good idea to exit with an error code in case something + # unexpected happens. + # The process module logs everything printed to stdout by actors into + # the server log, but marks them as `Error` in case the actor process + # exits with a code != 0, making debugging somewhat easier. + exit(-1) + +def on_tocheck(args, actor_name, user_id): + """ + Function called when an user returns control and the connected machine is + configured to go to state `ToCheck` instead of `Free` in that case. + + user_id contains the UID of the manager expected to check the machine. + The user that used the machine beforehand has to be taken from the last + user field using the API (via e.g. the mobile app) + """ + if args.verbose > 2: + print("on_tocheck called!") + if not args.quiet: + print("process called with unexpected combo id %s and state 'ToCheck'" % actor_name) + exit(-1) + +def on_blocked(args, actor_name, user_id): + """ + Function called when an manager marks the connected machine as `Blocked` + + user_id contains the UID of the manager that blocked the machine + """ + if args.verbose > 2: + print("on_blocked called!") + if not args.quiet: + print("process called with unexpected combo id %s and state 'Blocked'" % actor_name) + exit(-1) + +def on_disabled(args, actor_name): + """ + Function called when the connected machine is marked `Disabled` + """ + if not args.quiet: + print("process called with unexpected combo id %s and state 'Disabled'" % actor_name) + exit(-1) + +def on_reserve(args, actor_name, user_id): + """ + Function called when the connected machine has been reserved by somebody. + + user_id contains the UID of the reserving user. + """ + if not args.quiet: + print("process called with unexpected combo id %s and state 'Reserved'" % actor_name) + exit(-1) + + +def main(args): + """ + Python example actor + + This is an example how to use the `process` actor type to run a Python script. + """ + + if args.verbose is not None: + if args.verbose == 1: + print("verbose output enabled") + elif args.verbose == 2: + print("loud output enabled!") + elif args.verbose == 3: + print("LOUD output enabled!!!") + elif args.verbose > 4: + print("Okay stop you're being ridiculous.") + sys.exit(-2) + else: + args.verbose = 0 + + # You could also check the actor name here and call different functions + # depending on that variable instead of passing it to the state change + # methods. + + new_state = args.state + if new_state == "free": + on_free(args, args.name) + elif new_state == "inuse": + on_use(args, args.name, args.userid) + elif new_state == "tocheck": + on_tocheck(args, args.name, args.userid) + elif new_state == "blocked": + on_blocked(args, args.name, args.userid) + elif new_state == "disabled": + on_disabled(args, args.name) + elif new_state == "reserved": + on_reserve(args, args.name, args.userid) + else: + print("Process actor called with unknown state %s" % new_state) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + # Parameters are passed to the Process actor as follows: + # 1. the contents of params.args, split by whitespace as separate args + # 2. the configured id of the actor (e.g. "DoorControl1") + # 3. the new state as one of [free|inuse|tocheck|blocked|disabled|reserved] + + parser.add_argument("-q", "--quiet", help="be less verbose", action="store_true") + parser.add_argument("-v", "--verbose", help="be more verbose", action="count") + + parser.add_argument("name", + help="name of this actor as configured in bffh.dhall" + ) + + # We parse the new state using subparsers so that we only require a userid + # in case it's a state that sets one. + subparsers = parser.add_subparsers(required=True, dest="state") + + parser_free = subparsers.add_parser("free") + + parser_inuse = subparsers.add_parser("inuse") + parser_inuse.add_argument("userid", help="The user that is now using the machine") + + parser_tocheck = subparsers.add_parser("tocheck") + parser_tocheck.add_argument("userid", help="The user that should go check the machine") + + parser_blocked = subparsers.add_parser("blocked") + parser_blocked.add_argument("userid", help="The user that marked the machine as blocked") + + parser_disabled = subparsers.add_parser("disabled") + + parser_reserved = subparsers.add_parser("reserved") + parser_reserved.add_argument("userid", help="The user that reserved the machine") + + args = parser.parse_args() + main(args) diff --git a/ansible/deploy.yaml b/ansible/deploy.yaml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/environments/prod/default.env b/ansible/environments/prod/default.env new file mode 100644 index 0000000..e69de29 diff --git a/ansible/environments/prod/group_vars/all/001_env_specific.yaml b/ansible/environments/prod/group_vars/all/001_env_specific.yaml new file mode 100644 index 0000000..fd0f6a2 --- /dev/null +++ b/ansible/environments/prod/group_vars/all/001_env_specific.yaml @@ -0,0 +1,5 @@ +authorized_keys: + - user: krispin + key: ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAEOF7puj/P382S7cutdxApmJ7Zqv4QrKF61ebmzcRfI57Zb3cmU+hi6ziivPE4CQlsJkiZBNGTseuQcr5MwGkMfmgC5zOFCL4yKmAL/chr4B7jKUPcnJlnvjmzknZJtFKQKlxwoljuqj8hLXSOKj09HaYN9Cd8ypbIR9FnXqick/IX6KQ== + - user: nanu + key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDX8GaKakHw2CpCyiLkuC6DtTAIDC6cWQXa1nPHNQ7Cl8aeSa0g8f8BNvaD2icqlKze1E9oi6GgJgVgYU1h64BKaU88Z5ANh3nS1wCWk8UZtyL8XjyqPPvWI2DXNzTtRjbYmOWlQBtZETTrQHTDG0qOb3Bj0oDft1vH1sT/IJ9ixsYhHCqam5sxP2TahIBC0KOy61WI7dBfe85KrDE7kCCGXujXnfJn3ivIXxccMW/zgQXYES04h8AvILyHK9u1IeBbzCZ+osjW8mh4UqBanWD+xANSIJBtMAckYK9zXILCyghdCx4Qw8Lqwo4v4bqIKtIiyrIc8IIi2rNAsYUdNvA/ diff --git a/ansible/environments/prod/hosts.yaml b/ansible/environments/prod/hosts.yaml new file mode 100644 index 0000000..e687c2b --- /dev/null +++ b/ansible/environments/prod/hosts.yaml @@ -0,0 +1,6 @@ +all: + hosts: + oklab: + ansible_connection: paramiko + ansible_user: ok + ansible_host: "{{OKLAB_HOST}}" \ No newline at end of file diff --git a/ansible/environments/prod/secrets.yaml b/ansible/environments/prod/secrets.yaml new file mode 100644 index 0000000..0937030 --- /dev/null +++ b/ansible/environments/prod/secrets.yaml @@ -0,0 +1,6 @@ +$ANSIBLE_VAULT;1.2;AES256;prod +61653263353331653236653638643639386461613865636332613831643263663831393335373763 +3833326161323931303962393738383364346365313365650a373766383132653539306331396634 +65333138323536336432353565373064316663366363666661623939386663633232383832336261 +3532616566343135300a383232356438313138396530663832383531343161626336363430343762 +39326432613634346164386338386365356366316265373237316566383562663932 diff --git a/ansible/requirements.yaml b/ansible/requirements.yaml new file mode 100644 index 0000000..cbf74e6 --- /dev/null +++ b/ansible/requirements.yaml @@ -0,0 +1,5 @@ +collections: + - community.docker + - ansible.posix + - community.general +roles: [] \ No newline at end of file diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml new file mode 100644 index 0000000..456ace5 --- /dev/null +++ b/ansible/roles/common/tasks/main.yml @@ -0,0 +1,7 @@ +--- +- name: Set up all authorized keys + ansible.posix.authorized_key: + user: '{{ ansible_user }}' + state: present + key: '{{ item.key }}' + loop: '{{ authorized_keys }}' \ No newline at end of file diff --git a/ansible/setup.yaml b/ansible/setup.yaml new file mode 100644 index 0000000..cbf8744 --- /dev/null +++ b/ansible/setup.yaml @@ -0,0 +1,7 @@ +--- +- name: Setup all hosts with common behaviour + hosts: all + roles: + - common + tags: + - common \ No newline at end of file diff --git a/config/bffh/bffh.dhall b/config/bffh/bffh.dhall new file mode 100644 index 0000000..c7e9440 --- /dev/null +++ b/config/bffh/bffh.dhall @@ -0,0 +1,237 @@ +{- Main configuration file for bffh + - ================================ + - + - In this configuration file you configure almost all parts of how bffh operates, but most importantly: + - * Machines + - * Initiators and Actors + - * Which Initiators and Actors relate to which machine(s) + - * Roles and the permissions granted by them + -} + +-- The config is in the configuration format/language dhall. You can find more information about dhall over at +-- https://dhall-lang.org + +-- (Our) Dhall is somewhat similar to JSON and YAML in that it expects a top-level object containing the +-- configuration values +{ + -- Configure the addresses and ports bffh listens on + listens = [ + -- BFFH binds a port for every listen object in this array. + -- Each listen object is of the format { address = , port = } + -- If you don't specify a port bffh will use the default of `59661` + -- 'address' can be a IP address or a hostname + -- If bffh can not bind a port for the specified combination if will log an error but *continue with the remaining ports* + { address = "127.0.0.1", port = 59661 }, + { address = "::1", port = 59661 }, + { address = "steak.fritz.box", port = 59661 } + ], + + -- Configure TLS. BFFH requires a PEM-encoded certificate and the associated key as two separate files + certfile = "examples/self-signed-cert.pem", + keyfile = "examples/self-signed-key.pem", + + -- BFFH right now requires a running MQTT broker. + mqtt_url = "tcp://localhost:1883", + + -- Path to the database file for bffh. bffh will in fact create two files; ${db_path} and ${db_path}.lock. + -- BFFH will *not* create any directories so ensure that the directory exists and the user running bffh has write + -- access into them. + db_path = "/tmp/bffh", + + -- Audit log path. Bffh will log state changes into this file, one per line. + -- Audit log entries are for now JSON: + -- {"timestamp":1641497361,"machine":"Testmachine","state":{"state":{"InUse":{"uid":"Testuser","subuid":null,"realm":null}}}} + auditlog_path = "/tmp/bffh.audit", + + -- In dhall you can also easily import definitions from other files, e.g. you could write + -- roles = ./roles.dhall + roles = { + -- Role definitions + -- A role definition is of the form + -- rolename = { + -- parents = [], + -- permissions = [], + -- } + -- + -- Role names are case sensitive, so RoleName != rolename. + -- + -- If you want either parents or permissions to be empty its best to completely skip it: + testrole = { + permissions = [ "lab.some.admin" ] + }, + somerole = { + parents = ["testparent"], + -- "Permissions" are formatted as Perm Rules, so you can use the wildcards '*' and '+' + permissions = [ "lab.test.*" ] + }, + -- Roles can inherit from each other. In that case a member of e.g. 'somerole' that inherits from + -- 'testparent' will have all the permissions of 'somerole' AND 'testparent' assigned to them. + -- Right now permissions are stricly additive so you can't take a permission away in a child role that a parent + -- role grants. + testparent = { + permissions = [ + "lab.some.write", + "lab.some.read", + "lab.some.disclose" + ] + } + }, + + -- Configure machines + -- "Machines" (which in future will be more appropiately named "resources") are the main thing bffh is concerned + -- with. + -- You can define an almost limitless amount of machines (well 2^64 - 1, so 18_446_744_073_709_551_615 to be precise) + -- Each of these machines can then have several "actors" and "initiators" assigned + machines = { + Testmachine = { + -- A machine comes with two "names". The id above ("Testmachine") and the "name" ("MachineA"). + -- The id is what you'll use in the config format and is strictly limited to alphanumeric characters and '_' + -- and must begin with a letter. Most importantly you CAN NOT use '-' or spaces in an identifier + -- (dhall makes this technically possible but you can break things in subtle ways) + + -- REQUIRED. The "name" of a machine is what will be presented to humans. It can contain all unicode + -- including spaces and nonprintable characters. + -- A name SHOULD be short but unique. + name = "MachineA", + + -- OPTIONAL. A description can be assigned to machines. It will also only be shown to humans. Thus it is + -- once again limited only to unicode. If you want to provide your users with important additional + -- information other than the name this is the place to do it. + description = "A test machine", + + -- OPTIONAL. If you have a wiki going into more detail how to use a certain machine or what to keep in + -- mind when using it you can provide a URL here that will be presented to users. + wiki = "https://wiki.example.org/machineA", + + -- OPTIONAL. You can assign categories to machines to allow clients to group/filter machines by them. + category = "Testcategory", + + -- REQUIRED. + -- Each machine MUST have *all* Permission levels assigned to it. + -- Permissions aren't PermRules as used in the 'roles' definitions but must be precise without wildcards. + -- Permission levels aren't additive, so a user having 'manage' permission does not automatically get + -- 'read' or 'write' permission. + + -- (Note, disclose is not fully implemented at the moment) + -- Users lacking 'disclose' will not be informed about this machine in any way and it will be hidden from + -- them in the client. Usually the best idea is to assign 'read' and 'disclose' to the same permission. + disclose = "lab.test.read", + + -- Users lacking 'read' will be shown a machine including name, description, category and wiki but not + -- it's current state. The current user is not disclosed. + read = "lab.test.read", + + -- The 'write' permission allows to 'use' the machine. + write = "lab.test.write", + + -- Manage represents the 'superuser' permission. Users with this permission can force set any state and + -- read out the current user + manage = "lab.test.admin" + }, + Another = { + wiki = "test_another", + category = "test", + disclose = "lab.test.read", + manage = "lab.test.admin", + name = "Another", + read = "lab.test.read", + write = "lab.test.write" + }, + Yetmore = { + description = "Yet more test machines", + disclose = "lab.test.read", + manage = "lab.test.admin", + name = "Yetmore", + read = "lab.test.read", + write = "lab.test.write" + } + }, + + -- Actor configuration. Actors are how bffh affects change in the real world by e.g. switching a power socket + -- using a shelly + actors = { + -- Actors similarly to machines have an 'id'. This id (here "Shelly1234") is limited to Alphanumeric ASCII + -- and must begin with a letter. + Shelly1234 = { + -- Actors are modular pieces of code that are loaded as required. The "Shelly" module will send + -- activation signals to a shelly switched power socket over MQTT + module = "Shelly", + -- Actors can have arbitrary parameters passed to them, varying by actor module. + params = { + -- For Shelly you can configure the MQTT topic segment it uses. Shellies listen to a specific topic + -- containing their name (which is usually of the form "shelly_" but can be changed). + -- If you do not configure a topic here the actor will use it's 'id' (in this case "Shelly1234"). + topic = "Topic1234" + } + }, + + Bash = { + -- The "Process" module runs a given script or command on state change. + -- bffh invoces the given cmd as `$ ${cmd} ${args} ${id} ${state}` so e.g. as + -- `$ ./examples/actor.sh your ad could be here Bash inuse` + module = "Process", + params = { + -- which is configured by the (required) 'cmd' parameter. Paths are relative to PWD of bffh. Systemd + -- and similar process managers may change this PWD so it's usually the most future-proof to use + -- absolute paths. + cmd = "./examples/actor.sh", + -- You can pass static args in here, these will be passed to every invocation of the command by this actor. + -- args passed here are split by whitespace, so these here will be passed as 5 separate arguments + args = "your ad could be here" + } + }, + + DoorControl1 = { + -- This actor calls the actor.py script in examples/ + -- It gets passed it's own name, so you can have several actors + -- from the same script. + -- If you need to pass more arguments to the command you can use the `args` key in + -- `params` as is done with the actor `Bash` + module = "Process", + -- the `args` are passed in front of all other parameters so they are best suited to + -- optional parameters like e.g. the verboseness + params = { cmd = "./examples/actor.py", args = "-vvv" } + }, + DoorControl2 = { + module = "Process", + params = { cmd = "./examples/actor.py" } + }, + DoorControl3 = { + -- This is an example for how it looks like if an actor is misconfigured. + -- the actor.py doesn't know anything about DoorControl3 and, if this actor is enabled, + -- will return with an error showing up in the server logs. + module = "Process", + params = { cmd = "./examples/actor.py" } + }, + + Bash2 = { module = "Process", params = { cmd = "./examples/actor.sh" , args = "this is a different one" }}, + FailBash = { module = "Process", params = { cmd = "./examples/fail-actor.sh" }} + }, + + -- Linkng up machines to actors + -- Actors need to be connected to machines to be useful. A machine can be connected to multiple actors, but one + -- actor can only be connected to one machine. + actor_connections = [ + { machine = "Testmachine", actor = "Shelly1234" }, + { machine = "Another", actor = "Bash" }, + { machine = "Yetmore", actor = "Bash2" }, + { machine = "Yetmore", actor = "FailBash"} + ], + + -- Initiators are configured almost the same way as Actors, refer to actor documentation for more details + -- The below '{=}' is what you need if you want to define *no* initiators at all and only use the API with apps + -- to let people use machines. + initiators = {=}, + -- The "Dummy" initiator will try to use and return a machine as the given user every few seconds. It's good to + -- test your system but will spam your log so is disabled by default. + --initiators = { Initiator = { module = "Dummy", params = { uid = "Testuser" } } }, + + -- Linking up machines to initiators. Similar to actors a machine can have several initiators assigned but an + -- initiator can only be assigned to one machine. + -- The below is once again how you have to define *no* initiators. + init_connections = [] : List { machine : Text, initiator : Text }, + --init_connections = [{ machine = "Testmachine", initiator = "Initiator" }] + + instanceurl = "https://example.com", + spacename = "fablab-cb" +} diff --git a/config/bffh/users.toml b/config/bffh/users.toml new file mode 100644 index 0000000..4c4e83d --- /dev/null +++ b/config/bffh/users.toml @@ -0,0 +1,173 @@ +[Admin1] +roles = ["Admin"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[Admin2] +roles = ["Admin"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerA1] +roles = ["ManageA", "UseA", "ReadA", "DiscloseA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerA2] +roles = ["ManageA", "UseA", "ReadA", "DiscloseA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerB1] +roles = ["ManageB", "UseB", "ReadB", "DiscloseB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerB2] +roles = ["ManageB", "UseB", "ReadB", "DiscloseB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerC1] +roles = ["ManageC", "UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerC2] +roles = ["ManageC", "UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerABC1] +roles = ["ManageA", "UseA", "ReadA", "DiscloseA", "ManageB", "UseB", "ReadB", "DiscloseB", "ManageC", "UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[ManagerABC2] +roles = ["ManageA", "UseA", "ReadA", "DiscloseA", "ManageB", "UseB", "ReadB", "DiscloseB", "ManageC", "UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerA1] +roles = ["UseA", "ReadA", "DiscloseA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerA2] +roles = ["UseA", "ReadA", "DiscloseA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerB1] +roles = ["UseB", "ReadB", "DiscloseB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerB2] +roles = ["UseB", "ReadB", "DiscloseB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerC1] +roles = ["UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerC2] +roles = ["UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerABC1] +roles = ["UseA", "ReadA", "DiscloseA", "UseB", "ReadB", "DiscloseB", "UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerABC2] +roles = ["UseA", "ReadA", "DiscloseA", "UseB", "ReadB", "DiscloseB", "UseC", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestA1] +roles = ["ReadA", "DiscloseA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestA2] +roles = ["ReadA", "DiscloseA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestB1] +roles = ["ReadB", "DiscloseB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestB2] +roles = ["ReadB", "DiscloseB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestC1] +roles = ["ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestC2] +roles = ["ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestABC1] +roles = ["ReadA", "DiscloseA", "ReadB", "DiscloseB", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[GuestABC2] +roles = ["ReadA", "DiscloseA", "ReadB", "DiscloseB", "ReadC", "DiscloseC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerQRA] +roles = ["UseA", "ReadA"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerQRB] +roles = ["UseB", "ReadB"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +[MakerQRC] +roles = ["UseC", "ReadC"] +passwd = "secret" +noot = "noot!" +cardkey = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \ No newline at end of file diff --git a/config/cert/cert.pem b/config/cert/cert.pem new file mode 100644 index 0000000..f771f32 --- /dev/null +++ b/config/cert/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIUD/WP9/ClkcITVEE1ApyenpySXkswDQYJKoZIhvcNAQEL +BQAwQTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy +bGluMRAwDgYDVQQKDAdSTEtNIFVHMB4XDTIyMDQyMDEzNTk1MFoXDTIzMDQyMDEz +NTk1MFowQTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwG +QmVybGluMRAwDgYDVQQKDAdSTEtNIFVHMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAtlDacP0s0CjC5mP7pe2/uAo7nrP2WHztnG9ougbAcmSnmOCNWxYo +3ItGZQ4morGqTndx1yrr7/ZXVmqvvxtbcwQc99u4KFw9DrzCr/5la5SJv/KsBOW4 +mjNNPJY79DKsULuOo6nqZGUFNhk+nbFSjMy684zsIvj6YNeYE4lvPGVtQ+buBlep +FjYwyFgezpbdYnVPNKCCEag3Pgxi2Sxys9vaaUIP/BpMrLXXARk5sFHV5kiQRRZ6 +mw7hQz9Sb7BbQHeH1ejTLUNSTpHZ5fdptVTQRwt2Er5FgLcBPwckGymOCSsg8Bop +N6zFutybVl0vYK0KkslADLo+S8/W81ckKpUYFnk0zw9ET8LlrMnzc9jfV5BMtijz +sKArOC/ALLXz5FiPfpq+vVpqy354YkIy+n4xBKYpp9s3xeBpMLgupL/Tx7yB9Dxs +9Dp0vzDnx6UDHHo+U9OZYTmjy2oFxhM3lN73Hs2L2zgmWYUgksCQYJOUcXtGUW6C +nYLiSDJPqBoFSVGlUVSf9Aq4h23OWyRPD8GKcMQXVdFUEckgf5BRpGkxDigsDaAu +uN0QHCPw3fTg69xmIt0PxWGy+bEFSPZd83CtnklOAXTv7EnHb0HtZ1fDSqvbcGIi +A5LaCitC4Z5IaU7Ub23AY8BcjLnRopPIOVLrLvmznCoy0ntLBht/Z/0CAwEAAaNT +MFEwHQYDVR0OBBYEFOJ3+fyj1u6eou6MOktC5vUG2JPVMB8GA1UdIwQYMBaAFOJ3 ++fyj1u6eou6MOktC5vUG2JPVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggIBAE0eleTJs87FJ9Kuex/8NNZXs+4OjqetPbIJV32+IvIht1c51Bbo0MrS +7RdE4MIj5XyC6vpk+vpb/rnFr8Q655J7Ao/iVhwIW9k8Y4uJL5YvIrJyM9w/JWNa +Jp2f5Jc0xJmKaU7rkegokosg7y7vJGz+l2oeWcBFf6BQ/zcifUFGTah0u0qe2vGR +9dFZ07CAqawFvLsg/xDwmXkhEVWjB9CmwbbH5fgd9fpBL8wGiraaVCiVSwun9jzn +ylBCWF24BoI5UAjHgbPDAqwkbTLJaDPZF52AOT9M6UY9naJ8PflykwIqvAejZvbi +CrfUjqXS2F387VGJ9/xxzM2ZeMjWXT+FjOKJAZBf4r5CjsUvpBQZw/LiHfKzzTos +VauB6qJhIcqUUUpFdKeeyGkExfxsCuHfTk8n2g3kCYZUpgKt55gmFGUMqP8qXSko +6BfGIEtIEHdBdb5++IBIXINMj7mLYimk/iQkGWwQTN3RXCck6yN5lzUNNQ81Ea97 +dj4/UAzf9mztNVmZJMZ/sqVxUciGy+kr6JJi/4pUGIZh5IezHY5bS4dRAN0mQFzz +aYkyZlGrVrvex7zBeyO88erMnFMxFS1el9ms0Izu85NmkryWkg+U7yzJAFqJXDHT +an1Se25jGeyqyA0Y2soZ9GjxkTkOkXuPIYr+LdZPpd8ce0KI5ncg +-----END CERTIFICATE----- diff --git a/config/cert/key.pem b/config/cert/key.pem new file mode 100644 index 0000000..9b64f24 --- /dev/null +++ b/config/cert/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 ++cqdvrc3lDTZ3QIesrwgLuCGSQpj +-----END PRIVATE KEY----- diff --git a/config/mosquitto/mosquitto.conf b/config/mosquitto/mosquitto.conf new file mode 100644 index 0000000..d33a1a7 --- /dev/null +++ b/config/mosquitto/mosquitto.conf @@ -0,0 +1,3 @@ +persistence true +persistence_location /mosquitto/data/ +log_dest file /mosquitto/log/mosquitto.log \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..05351fd --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,28 @@ +version: "3.8" +services: + bffh: + image: registry.gitlab.com/fabinfra/fabaccess/bffh:development + ports: + - "59661:59661" + entrypoint: ["sh", "-c", "bffhd -c /etc/bffh/bffh.dhall --load=/etc/bffh/users.toml; bffhd -c /etc/bffh/bffh.dhall"] + environment: + - "BFFH_LOG=debug" + volumes: + # generate a sample config.toml by running "docker run registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest --print-default > examples/config.toml" from the project root. You may have to delete the ipv6 listen section. + - "./config/bffh:/etc/bffh" + - "./adapters:/usr/local/lib/bffh/adapters" + - "./config/cert:/etc/letsencrypt" + - data:/var/lib/bffh + links: + - mqtt + + mqtt: + image: eclipse-mosquitto:1.6.15 + ports: + - "1883:1883" + volumes: + - "./config/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf" + +volumes: + data: +