Compare commits
No commits in common. "20c0e0f5de181c79b741353f8445c365c7cdd27c" and "ae328f465c57d73d4de14e06c7ecef2fc57513aa" have entirely different histories.
20c0e0f5de
...
ae328f465c
@ -1,9 +1,9 @@
|
|||||||
# This configuration file was generated by `ameba --gen-config`
|
# This configuration file was generated by `ameba --gen-config`
|
||||||
# on 2024-07-01 13:11:14 UTC using Ameba version 1.6.1.
|
# on 2024-06-30 18:10:12 UTC using Ameba version 1.6.1.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the reported problems are removed from the code base.
|
# one by one as the reported problems are removed from the code base.
|
||||||
|
|
||||||
# Problems found: 11
|
# Problems found: 10
|
||||||
# Run `ameba --only Documentation/DocumentationAdmonition` for details
|
# Run `ameba --only Documentation/DocumentationAdmonition` for details
|
||||||
Documentation/DocumentationAdmonition:
|
Documentation/DocumentationAdmonition:
|
||||||
Description: Reports documentation admonitions
|
Description: Reports documentation admonitions
|
||||||
@ -12,7 +12,6 @@ Documentation/DocumentationAdmonition:
|
|||||||
- src/faaso.cr
|
- src/faaso.cr
|
||||||
- src/daemon.cr
|
- src/daemon.cr
|
||||||
- src/funko.cr
|
- src/funko.cr
|
||||||
- src/daemon-secrets.cr
|
|
||||||
- spec/faaso_spec.cr
|
- spec/faaso_spec.cr
|
||||||
Admonitions:
|
Admonitions:
|
||||||
- TODO
|
- TODO
|
||||||
|
@ -6,10 +6,10 @@ However, code running in docker containers like a funko does often needs
|
|||||||
access to secrets, such as passwords to databases. Let's use that as the
|
access to secrets, such as passwords to databases. Let's use that as the
|
||||||
example secret for the rest of the document.
|
example secret for the rest of the document.
|
||||||
|
|
||||||
Also, not all funkos should have access to all the secrets, and the
|
Also, not all funkos should have access to all the secrets, and the
|
||||||
"need to know" should be declarative in the funko's metadata.
|
"need to know" should be declarative in the funko's metadata.
|
||||||
|
|
||||||
## Problem 1: accessing secrets in the proxy container from the funkos
|
## Problem 1: accessing secrets in the proxy container from the funkos
|
||||||
|
|
||||||
Let's further assume that faaso-proxy has access *somehow* to all the secrets,
|
Let's further assume that faaso-proxy has access *somehow* to all the secrets,
|
||||||
identified by a name. So there is a "dbpass" secret that has "verysecret" as
|
identified by a name. So there is a "dbpass" secret that has "verysecret" as
|
||||||
@ -18,32 +18,4 @@ it's very secret content.
|
|||||||
Also let's assume the proxy has access to a folder in the server filesystem,
|
Also let's assume the proxy has access to a folder in the server filesystem,
|
||||||
`/secrets` via something like a bind mount.
|
`/secrets` via something like a bind mount.
|
||||||
|
|
||||||
If the proxy has access to the funko metadata, it can access a declaration of
|
## Problem 2: how can the proxy know the secrets without keeping them in the image?
|
||||||
what secrets the funko needs.
|
|
||||||
|
|
||||||
Alternatively ... convention!
|
|
||||||
|
|
||||||
Secrets for the funko foo are called foo-{name}, so our example is called foo-dbpass.
|
|
||||||
|
|
||||||
So, the proxy can periodically examine its secret store and populate a folder
|
|
||||||
`/secrets/foo` with a `dbpass` file containing "verysecret".
|
|
||||||
|
|
||||||
If on starting a funko we always do a bind mount of `/secrets/foo` to `/secrets`
|
|
||||||
then it will always have its secrets in place.
|
|
||||||
|
|
||||||
## Problem 2: how can the proxy know the secrets without keeping them in the image?
|
|
||||||
|
|
||||||
They can't be shipped via the image, so they need to be injected via the admin API.
|
|
||||||
|
|
||||||
Let's give it a /secret endpoint and have all the usual REST stuff there.
|
|
||||||
|
|
||||||
## The Good
|
|
||||||
|
|
||||||
* It should work
|
|
||||||
* No secrets are unencrypted at rest in images
|
|
||||||
|
|
||||||
## The Bad
|
|
||||||
|
|
||||||
* Secrets are unencrypted at rest in the server filesystem
|
|
||||||
* Secrets are only sort-of-persistent? If the proxy is restarted, it will need
|
|
||||||
the secrets reinjected, or we need a persistent secret store in the server filesystem.
|
|
@ -1,59 +0,0 @@
|
|||||||
require "kemal"
|
|
||||||
|
|
||||||
module Proxy
|
|
||||||
@@current_config = File.read("tinyproxy.conf")
|
|
||||||
|
|
||||||
# Get current proxy config
|
|
||||||
get "/proxy/" do
|
|
||||||
@@current_config
|
|
||||||
end
|
|
||||||
|
|
||||||
# Bump proxy config to current docker state, returns
|
|
||||||
# new proxy config
|
|
||||||
patch "/proxy/" do
|
|
||||||
Log.info { "Updating routing" }
|
|
||||||
# Get all the funkos, create routes for them all
|
|
||||||
update_proxy_config
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.update_proxy_config
|
|
||||||
docker_api = Docr::API.new(Docr::Client.new)
|
|
||||||
containers = docker_api.containers.list(all: true)
|
|
||||||
|
|
||||||
funkos = [] of String
|
|
||||||
containers.each { |container|
|
|
||||||
names = container.names.select &.starts_with? "/faaso-"
|
|
||||||
next if names.empty?
|
|
||||||
funkos << names[0][7..]
|
|
||||||
}
|
|
||||||
funkos.sort!
|
|
||||||
|
|
||||||
config = %(
|
|
||||||
Port 8888
|
|
||||||
Listen 0.0.0.0
|
|
||||||
Timeout 600
|
|
||||||
Allow 0.0.0.0/0
|
|
||||||
ReverseOnly Yes
|
|
||||||
ReverseMagic Yes
|
|
||||||
ReversePath "/admin/" "http://127.0.0.1:3000/"
|
|
||||||
) + funkos.map { |funko| %(ReversePath "/faaso/#{funko}/" "http://#{funko}:3000/") }.join("\n")
|
|
||||||
|
|
||||||
if @@current_config != config
|
|
||||||
File.open("tinyproxy.conf", "w") do |file|
|
|
||||||
file << config
|
|
||||||
end
|
|
||||||
# Reload config
|
|
||||||
Process.run(command: "/usr/bin/killall", args: ["-USR1", "tinyproxy"])
|
|
||||||
@@current_config = config
|
|
||||||
end
|
|
||||||
config
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Update proxy config once a second
|
|
||||||
spawn do
|
|
||||||
loop do
|
|
||||||
Proxy.update_proxy_config
|
|
||||||
sleep 1.second
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,44 +0,0 @@
|
|||||||
require "kemal"
|
|
||||||
|
|
||||||
SECRETS = Hash(String, String).new
|
|
||||||
SECRET_PATH = "./secrets/"
|
|
||||||
|
|
||||||
# TODO: sanitize all inputs
|
|
||||||
|
|
||||||
# Store secrets in a tree of files
|
|
||||||
def update_secrets
|
|
||||||
# Save new secrets
|
|
||||||
SECRETS.map do |_name, value|
|
|
||||||
funko, name = _name.split("-", 2)
|
|
||||||
funko_dir = Path.new(SECRET_PATH, funko)
|
|
||||||
Dir.mkdir_p(funko_dir)
|
|
||||||
File.write(Path.new(funko_dir, name), value)
|
|
||||||
end
|
|
||||||
# Delete secrets not in the hash
|
|
||||||
Dir.glob(Path.new(SECRET_PATH, "*")).each do |funko_dir|
|
|
||||||
funko = File.basename(funko_dir)
|
|
||||||
Dir.glob(Path.new(funko_dir, "*")).each do |secret_file|
|
|
||||||
name = File.basename(secret_file)
|
|
||||||
unless SECRETS.has_key?("#{funko}-#{name}")
|
|
||||||
File.delete(secret_file)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Gets a secret in form {"name": "funko_name-secret_name", "value": "secret_value"}
|
|
||||||
post "/secrets/" do |env|
|
|
||||||
name = env.params.json["name"].as(String)
|
|
||||||
value = env.params.json["value"].as(String)
|
|
||||||
SECRETS[name] = value
|
|
||||||
update_secrets
|
|
||||||
halt env, status_code: 201, response: "Created"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Deletes a secret from the disk and memory
|
|
||||||
delete "/secrets/:name/" do |env|
|
|
||||||
name = env.params.url["name"]
|
|
||||||
SECRETS.delete(name)
|
|
||||||
update_secrets
|
|
||||||
halt env, status_code: 204, response: "Deleted"
|
|
||||||
end
|
|
@ -1,7 +1,5 @@
|
|||||||
require "./daemon-secrets.cr"
|
|
||||||
require "./daemon-proxyconf.cr"
|
|
||||||
require "compress/gzip"
|
|
||||||
require "crystar"
|
require "crystar"
|
||||||
|
require "compress/gzip"
|
||||||
require "docr"
|
require "docr"
|
||||||
require "kemal-basic-auth"
|
require "kemal-basic-auth"
|
||||||
require "kemal"
|
require "kemal"
|
||||||
@ -10,6 +8,51 @@ require "uuid"
|
|||||||
# FIXME: make configurable
|
# FIXME: make configurable
|
||||||
basic_auth "admin", "admin"
|
basic_auth "admin", "admin"
|
||||||
|
|
||||||
|
current_config = File.read("tinyproxy.conf")
|
||||||
|
|
||||||
|
# Get current proxy config
|
||||||
|
get "/proxy/" do
|
||||||
|
current_config
|
||||||
|
end
|
||||||
|
|
||||||
|
# Bump proxy config to current docker state, returns
|
||||||
|
# new proxy config
|
||||||
|
patch "/proxy/" do
|
||||||
|
Log.info { "Updating routing" }
|
||||||
|
# Get all the funkos, create routes for them all
|
||||||
|
docker_api = Docr::API.new(Docr::Client.new)
|
||||||
|
containers = docker_api.containers.list(all: true)
|
||||||
|
|
||||||
|
funkos = [] of String
|
||||||
|
containers.each { |container|
|
||||||
|
names = container.names.select &.starts_with? "/faaso-"
|
||||||
|
next if names.empty?
|
||||||
|
funkos << names[0][7..]
|
||||||
|
}
|
||||||
|
|
||||||
|
funkos.sort!
|
||||||
|
|
||||||
|
proxy_config = %(
|
||||||
|
Port 8888
|
||||||
|
Listen 0.0.0.0
|
||||||
|
Timeout 600
|
||||||
|
Allow 0.0.0.0/0
|
||||||
|
ReverseOnly Yes
|
||||||
|
ReverseMagic Yes
|
||||||
|
ReversePath "/admin/" "http://127.0.0.1:3000/"
|
||||||
|
) + funkos.map { |funko| %(ReversePath "/faaso/#{funko}/" "http://#{funko}:3000/") }.join("\n")
|
||||||
|
|
||||||
|
if current_config != proxy_config
|
||||||
|
File.open("tinyproxy.conf", "w") do |file|
|
||||||
|
file << proxy_config
|
||||||
|
end
|
||||||
|
# Reload config
|
||||||
|
Process.run(command: "/usr/bin/killall", args: ["-USR1", "tinyproxy"])
|
||||||
|
current_config = proxy_config
|
||||||
|
end
|
||||||
|
proxy_config
|
||||||
|
end
|
||||||
|
|
||||||
# Bring up the funko
|
# Bring up the funko
|
||||||
get "/funko/:name/up/" do |env|
|
get "/funko/:name/up/" do |env|
|
||||||
name = env.params.url["name"]
|
name = env.params.url["name"]
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
Port 8888
|
Port 8888
|
||||||
Listen 0.0.0.0
|
Listen 0.0.0.0
|
||||||
Timeout 600
|
Timeout 600
|
||||||
Allow 0.0.0.0/0
|
Allow 0.0.0.0/0
|
||||||
ReverseOnly Yes
|
ReverseOnly Yes
|
||||||
ReverseMagic Yes
|
ReverseMagic Yes
|
||||||
ReversePath "/admin/" "http://127.0.0.1:3000/"
|
ReversePath "/admin/" "http://127.0.0.1:3000/"
|
||||||
|
ReversePath "/faaso/hello/" "http://hello:3000/"
|
Loading…
Reference in New Issue
Block a user