WIP for on-the-fly users.
parent
ab9a76326e
commit
c8c0be9804
|
@ -5,3 +5,7 @@ ports: http=80, https=443
|
||||||
reload-command: kill -HUP ${SERVICE_PID}
|
reload-command: kill -HUP ${SERVICE_PID}
|
||||||
|
|
||||||
%configuration nginx.conf
|
%configuration nginx.conf
|
||||||
|
|
||||||
|
# They’re defined in the template, be careful to match.
|
||||||
|
%file access.log
|
||||||
|
%file error.log
|
||||||
|
|
|
@ -14,5 +14,8 @@ dependencies:
|
||||||
git: https://git.karchnu.fr/WeirdOS/recipes-parser
|
git: https://git.karchnu.fr/WeirdOS/recipes-parser
|
||||||
crinja:
|
crinja:
|
||||||
github: straight-shoota/crinja
|
github: straight-shoota/crinja
|
||||||
|
passwd:
|
||||||
|
git: https://git.karchnu.fr/WeirdOS/passwd.cr
|
||||||
|
branch: master
|
||||||
|
|
||||||
license: MIT
|
license: MIT
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require "crinja"
|
require "crinja"
|
||||||
|
|
||||||
|
require "passwd"
|
||||||
|
|
||||||
require "./service/service.cr"
|
require "./service/service.cr"
|
||||||
require "./config.cr"
|
require "./config.cr"
|
||||||
|
|
||||||
|
@ -8,7 +10,7 @@ def sanitize_path(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
class Service
|
class Service
|
||||||
alias CrinjaHash = Hash(String, Hash(String, Int32) | String | Crinja::Callable::Instance | Nil)
|
alias CrinjaHash = Hash(String, Hash(String, Int32) | String | Crinja::Callable::Instance | Int32 | Nil)
|
||||||
def to_genconfig
|
def to_genconfig
|
||||||
CrinjaHash.new.tap do |entry|
|
CrinjaHash.new.tap do |entry|
|
||||||
entry["name"] = name
|
entry["name"] = name
|
||||||
|
@ -18,6 +20,13 @@ class Service
|
||||||
entry["domain"] = domain
|
entry["domain"] = domain
|
||||||
entry["ports"] = ports
|
entry["ports"] = ports
|
||||||
|
|
||||||
|
user = Passwd.new("/etc/passwd", "/etc/group")
|
||||||
|
.try &.get_user(user_name).not_nil!
|
||||||
|
|
||||||
|
entry["uid"] = user.uid
|
||||||
|
entry["gid"] = user.gid
|
||||||
|
entry["user"] = user.login
|
||||||
|
|
||||||
entry["consumers"] = Crinja.function do
|
entry["consumers"] = Crinja.function do
|
||||||
token = arguments.varargs[0].to_s
|
token = arguments.varargs[0].to_s
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,15 @@ module System
|
||||||
|
|
||||||
passwd = pointer.value
|
passwd = pointer.value
|
||||||
|
|
||||||
r = LibC.setgid passwd.pw_gid
|
become_user passwd.pw_uid, passwd.pw_uid
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.become_user(uid, gid)
|
||||||
|
r = LibC.setgid gid
|
||||||
raise Errno.new "setgid" if r != 0
|
raise Errno.new "setgid" if r != 0
|
||||||
|
|
||||||
r = LibC.setuid passwd.pw_uid
|
r = LibC.setuid uid
|
||||||
raise Errno.new "setuid" if r != 0
|
raise Errno.new "setuid" if r != 0
|
||||||
|
|
||||||
passwd
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
#def get_uid_gid(user_name : String)
|
#def get_uid_gid(user_name : String)
|
||||||
|
|
|
@ -2,6 +2,8 @@ require "yaml"
|
||||||
require "colorize"
|
require "colorize"
|
||||||
require "file_utils"
|
require "file_utils"
|
||||||
|
|
||||||
|
require "passwd"
|
||||||
|
|
||||||
require "./context.cr"
|
require "./context.cr"
|
||||||
require "./service_definition.cr"
|
require "./service_definition.cr"
|
||||||
require "./environment.cr"
|
require "./environment.cr"
|
||||||
|
@ -215,6 +217,7 @@ class Service
|
||||||
env["SERVICE_NAME"] = name
|
env["SERVICE_NAME"] = name
|
||||||
env["SERVICE_ROOT"] = root
|
env["SERVICE_ROOT"] = root
|
||||||
env["SERVICE_ID"] = full_id
|
env["SERVICE_ID"] = full_id
|
||||||
|
env["SERVICE_USER"] = user_name
|
||||||
if _pid = pid @context.pid_directory
|
if _pid = pid @context.pid_directory
|
||||||
env["SERVICE_PID"] = _pid.to_s
|
env["SERVICE_PID"] = _pid.to_s
|
||||||
end
|
end
|
||||||
|
@ -222,11 +225,10 @@ class Service
|
||||||
env["ENVIRONMENT"] = @environment.name
|
env["ENVIRONMENT"] = @environment.name
|
||||||
env["ENVIRONMENT_TYPE"] = @environment.type.to_s
|
env["ENVIRONMENT_TYPE"] = @environment.type.to_s
|
||||||
|
|
||||||
|
|
||||||
@providers.each do |token, provider|
|
@providers.each do |token, provider|
|
||||||
service_provider = @context.get_service_by_id provider
|
service_provider = @context.get_service_by_id provider
|
||||||
|
|
||||||
# FIXME: Warning?
|
# FIXME: Warning if mandatory?
|
||||||
next if service_provider.nil?
|
next if service_provider.nil?
|
||||||
|
|
||||||
env["#{token.upcase}_PROVIDER"] = provider
|
env["#{token.upcase}_PROVIDER"] = provider
|
||||||
|
@ -294,9 +296,13 @@ class Service
|
||||||
|
|
||||||
context.info "Creating #{file.name}"
|
context.info "Creating #{file.name}"
|
||||||
|
|
||||||
|
uid, gid = get_uid_gid
|
||||||
|
|
||||||
child = Process.fork do
|
child = Process.fork do
|
||||||
Dir.cd root
|
Dir.cd root
|
||||||
|
|
||||||
|
System.become_user uid, gid
|
||||||
|
|
||||||
Process.exec "sh", ["-c", creation_command],
|
Process.exec "sh", ["-c", creation_command],
|
||||||
output: Process::Redirect::Inherit,
|
output: Process::Redirect::Inherit,
|
||||||
error: Process::Redirect::Inherit,
|
error: Process::Redirect::Inherit,
|
||||||
|
@ -319,7 +325,11 @@ class Service
|
||||||
context.title "Starting #{to_s}"
|
context.title "Starting #{to_s}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_user_and_group!
|
||||||
|
|
||||||
|
uid, gid = get_uid_gid
|
||||||
FileUtils.mkdir_p root
|
FileUtils.mkdir_p root
|
||||||
|
File.chown root, uid, gid
|
||||||
|
|
||||||
build_files! context
|
build_files! context
|
||||||
|
|
||||||
|
@ -337,12 +347,7 @@ class Service
|
||||||
LibC.dup2 stdout_file.fd, 1
|
LibC.dup2 stdout_file.fd, 1
|
||||||
LibC.dup2 stderr_file.fd, 2
|
LibC.dup2 stderr_file.fd, 2
|
||||||
|
|
||||||
@reference.user.try do |user|
|
System.become_user uid, gid
|
||||||
unless System.become_user user
|
|
||||||
STDERR << "service: child could not setuid() to user '#{user}'.\n"
|
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Process.exec command, args,
|
Process.exec command, args,
|
||||||
chdir: (@reference.directory.try { |x| evaluate x } || root),
|
chdir: (@reference.directory.try { |x| evaluate x } || root),
|
||||||
|
@ -583,7 +588,11 @@ class Service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
remove_user_and_group!
|
||||||
|
|
||||||
File.delete "#{context.services_directory}/#{name}.#{@environment.name}.spec"
|
File.delete "#{context.services_directory}/#{name}.#{@environment.name}.spec"
|
||||||
|
|
||||||
|
FileUtils.rm_rf root
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_id?(id)
|
def is_id?(id)
|
||||||
|
@ -660,6 +669,34 @@ class Service
|
||||||
def get_consumers(token)
|
def get_consumers(token)
|
||||||
@context.services.select(&.consumes?(token, self))
|
@context.services.select(&.consumes?(token, self))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_name
|
||||||
|
full_id.sub('/', '.')
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_uid_gid
|
||||||
|
passwd = Passwd.new("/etc/passwd", "/etc/group")
|
||||||
|
|
||||||
|
user = passwd.get_user(user_name).not_nil!
|
||||||
|
|
||||||
|
{user.uid, user.gid}
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_user_and_group!
|
||||||
|
Passwd.new("/etc/passwd", "/etc/group").tap do |passwd|
|
||||||
|
return if passwd.get_user user_name
|
||||||
|
|
||||||
|
passwd.add_user user_name,
|
||||||
|
full_name: "Service[#{id}]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_user_and_group!
|
||||||
|
Passwd.new("/etc/passwd", "/etc/group").tap do |passwd|
|
||||||
|
passwd.remove_user user_name
|
||||||
|
passwd.remove_group user_name
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ events {
|
||||||
}
|
}
|
||||||
|
|
||||||
http {
|
http {
|
||||||
error_log /var/log/{{ service.id | replace("/", "_") }}_error.log warn;
|
error_log {{ service.root }}/error.log warn;
|
||||||
access_log /var/log/{{ service.id | replace("/", "_") }}_access.log;
|
access_log {{ service.root }}/access.log;
|
||||||
|
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
Loading…
Reference in New Issue