]> git.madduck.net Git - code/gsc.git/blob - README

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Initial checkin
[code/gsc.git] / README
1 gsc — Git service configuration
2 -------------------------------
3 2014-12-19-1306 madduck@madduck.net
4
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.
11
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.
18
19 gsc is an alternative way of doing things. In a nutshell:
20
21   - configuration is maintained in Git and something like gitolite can be used
22     to manage fine-grained access control;
23
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;
26
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.
31
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.
37
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.
42
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.
45
46 Set-up by example: nsd
47 ----------------------
48
49 Let's walk through a simple example and configure the nsd DNS server to be
50 configurable/manageable with gsc.
51
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
54      there.
55
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.
58
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):
64
65        command="make -sC target git_pull update",no-agent-forwarding,
66        no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding
67
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.
71
72      Commit the two files .gsc/poke-key and .gsc/poke-key.pub to the
73      repository.
74
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
78      /bin/sh).
79
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.
82
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.
89
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
93      central repo.
94
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
98      configuration.
99
100   6. Now you should be able to poke a host from your workstation:
101
102        ssh -Ti .gsc/poke-key -o UserKnownHostFile=.gsc/ssh_known_hosts \
103          nsd_update@grimble.example.org
104
105      which should print something like
106
107        make: *** No rule to make target 'git_pull'.  Stop.
108
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
111      well.
112
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.
117
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
120      (see further down).
121
122   8. Commit a file .gsc/pokehosts to the repository, listing each target
123      server one-per-line in user@host style, e.g.
124
125        nsd_update@grimble.example.org
126        nsd_update@grumble.example.org
127
128      The rest of each line is unused for now, but reserved for future use, so
129      don't put anything else there.
130
131   9. Now push your commits to the central repo, which should cause the hook to
132      poke both hosts, yielding the make error.
133
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.
138
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.
143
144 TODO:
145
146   - per-host branches
147   - how to recover from faulty pushes, e.g. if the server was taken down
148   - gitolite notes