All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 gsc — Git service configuration
2 -------------------------------
3 2014-12-19-1306 madduck@madduck.net
5 The following describes a method for the configuration of services, using Git
6 as a backend. A service in this context is e.g. a mail server like Postfix or
7 a DNS server like NSD, which runs on a Unix system and is configured using
8 files usually situated in the /etc directory. When those files are changed,
9 usually some steps have to be taken to fix up permissions, compile/merge
10 files, and reload the service.
12 These steps — editing configuration files and reloading services — are also
13 the domain of so-called configuration management systems, such as CFengine and
14 Puppet. While these are indispensable tools for the general management of
15 machines, it is often the case that the fine-grained configuration of
16 a complex mailserver requires more work to express in terms of the
17 configuration management syntax than there are benefits.
19 gsc is an alternative way of doing things. In a nutshell:
21 - configuration is maintained in Git and something like gitolite can be used
22 to manage fine-grained access control;
24 - upon push, a repo-side hook runs, reads from the repository a number of
25 hosts to poke and proceeds to do just that using SSH forced commands;
27 - a dedicated user on each target machine receives the poke, updates the
28 local Git repository and executes an in-tree Makefile, which is
29 responsible for the integration of the changes into the running service,
30 possibly using in-tree host-specific parameters.
32 A word for the security-conscious
33 '''''''''''''''''''''''''''''''''
34 It is true that one might question the use of in-tree configuration files and
35 the Makefile. After all, it allows anyone with write-access to the Git repo to
36 impersonate the dedicated poke user, though not without leaving a trace.
38 In the end it's a matter of trust and if you're ready to assume that someone
39 who's supposed to be able to configure a given service on a machine can't
40 really do any harm by impersonating the user designed to configure the given
41 service, then you're on the safe side.
43 The benefit of this approach is that it avoids operation as root whenever
44 possible, defering to sudo for just those steps that require root privileges.
46 Set-up by example: nsd
47 ----------------------
49 Let's walk through a simple example and configure the nsd DNS server to be
50 configurable/manageable with gsc.
52 0. We'll start with the assumption that the contents of /etc/nsd is already
53 tracked in a central Git repository and that trusted DNS admins can push
56 We'll also assume that changes to the nsd config should be pushed to two
57 DNS servers, grimble.example.org and grumble.example.org.
59 1. Create a new, password-less (!) SSH keyfile using ssh-keygen on your
60 local machine (which needs a clone of the above Git repo), store the key
61 into .gsc/poke-key[.pub] inside that repo, and edit the public keyfile by
62 prepending the following to the first (and only) line (broken here into
63 two lines for readability):
65 command="make -sC target git_pull update",no-agent-forwarding,
66 no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding
68 You can also add a from="" limit as per the sshd(8) manpage, although
69 there are benefits in not doing that, namely the ability for anyone with
70 access to the repo to poke the servers.
72 Commit the two files .gsc/poke-key and .gsc/poke-key.pub to the
75 2. On the two "poke" hosts, make sure you have Git, make and sudo installed.
76 Then add a new system user, e.g. nsd_update (with group nsd_update,
77 disabled password, home directory /var/local/nsd_update, and shell
80 3. Copy .gsc/poke-key.pub to ~nsd_update/.ssh/authorized_keys and make sure
81 to run `chown -R nsd_update ~nsd_update/.ssh` or similar.
83 4. Clone the Git repo with --shared=group to /etc/nsd (or /etc/nsd3) and
84 similarly chown it, so that the poke user can maintain it without root
85 rights. Consequentially, the user "nsd" needs to be able to read
86 (possibly even write) the files in this repository, so you need to either
87 add nsd to the group nsd_update and ensure g+rwX permissions (using the
88 Makefile, see below), or employ ACLs.
90 Make sure that the nsd_update user can pull from the repo, either by
91 making it publicly available, or by setting up a new password-less SSH
92 key for nsd_update on each host, which is then given access to the
95 5. Create a symlink ~nsd_update/target to /etc/nsd (or whatever directory
96 you chose). This was done to avoid having to make /etc/nsd the
97 home directory of the update user and not hardcoding the location of the
100 6. Now you should be able to poke a host from your workstation:
102 ssh -Ti .gsc/poke-key -o UserKnownHostFile=.gsc/ssh_known_hosts \
103 nsd_update@grimble.example.org
105 which should print something like
107 make: *** No rule to make target 'git_pull'. Stop.
109 Do this for all hosts in pokehosts to populate .gsc/ssh_known_hosts
110 (verifying the fingerprints, of course), and then commit this file as
113 As we are using forced commands, it makes no difference what you put
114 after the user@host argument in the above. However, we may need this in
115 the future, so let's reserve it. Please refrain from using it and/or let
116 me know if you have any ideas.
118 7. Install the gsc-post-receive hook to hooks/post-receive in the central
119 git repo. When using gitolite, I suggest the use of per-repository hooks
122 8. Commit a file .gsc/pokehosts to the repository, listing each target
123 server one-per-line in user@host style, e.g.
125 nsd_update@grimble.example.org
126 nsd_update@grumble.example.org
128 The rest of each line is unused for now, but reserved for future use, so
129 don't put anything else there.
131 9. Now push your commits to the central repo, which should cause the hook to
132 poke both hosts, yielding the make error.
134 10. Now all that's left to do is write /etc/nsd/Makefile with at least the
135 targets git_pull and update, which should run git-pull (possibly with
136 --rebase) and then cause the appropriate next steps. Use sudo sparingly
137 for maximum security benefit.
139 Please refer to the examples/ directory in the gsc repository for
140 a simple example that works with nsd, and which also handles per-host
141 difference by parametrising e.g. IP addresses or commands needed to
142 reload/restart the service.
147 - how to recover from faulty pushes, e.g. if the server was taken down