1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
Wallet Implementation Notes
Introduction
Collected here are implementation notes about design decisions,
external interfaces, integration, internal structure, and related
issues. This document will mostly be of interest to people who want
to modify the wallet code or who are curious about its design.
This is now mostly of historical interest. For information about how
the wallet now works, see the documentation for each of the server
classes, the other design documents, and the man pages for the
programs. Some portions of this document may be inaccurate or not
reflect how the wallet system is currently implemented.
Server Issues
Interface
We need two interfaces for retrieving items, one which retrieves the
current stored item and one which generates a new item. This
particularly applies to keytabs. We also don't want new keytabs to be
generated for certain keys even by accident without an explicit action
taken, but for most keytabs we want to generate new keys each time.
So we need an interface like:
get keytab
Generates a new keytab normally, but retrieves the existing keytab
if we've marked the key as unchanging.
flag set unchanging
flag clear unchanging
Change the state to generate new keytabs each time or always try to
pull the existing key. This operation should probably be
privileged.
So if you want to generate a new key for a keytab that would otherwise
be persistant, mark it changing, download the new key, and then mark
it unchanging again.
Possibly need to do something about occasionally changing keys of
keytabs that are otherwise marked unchanging, or we're going to open
ourselves to brute force attacks.
ACL Management
Supported operations are: get, store, create (possibly triggered by a
get or store of something that didn't already exist), destroy, show,
and setting or clearing flags. Each of these need a separate ACL
potentially. Not sure if we're going to need separate ACLs for each
flag operation.
Administrators get implicit access to do anything except get and
store. They can give themselves get and store access just by changing
ACLs, of course, but it encourages sloppy ACLs to let them get and
store without an explicit ACL (administrators then end up relying on
that privilege and not reflecting it in ACLs). There does need to be
an ACL on create, but that should probably be implemented via some
sort of policy callout. The user will write a simple Perl function
that returns a default ACL given the object type and name if the
object doesn't already exist.
Owner rights provides get, store, show, and destroy, but not setting
or clearing flags. This can be overridden by more precise ACL
settings. So the ACL logic would go like this:
* If the user is an administrator and the operation isn't get or
store, operation is permitted.
* Otherwise, check the object. If it exists and has a setting for
that specific ACL, apply that ACL.
* If the object exists but with no specific ACL setting and the
operation is one of get, store, show, or destroy, apply the owner
ACL.
* If the object doesn't exist and the action is get, store, or
create, punt to a local policy if it exists and see if it returns a
default ACL.
I think the owner abstraction is worth it over just setting the ACL
for get, store, and show.
Flags
locked -- No operations permitted except show
unchanging -- Pull existing value from file store
For backends like secure files, all values are unchanging implicitly,
but I don't think we should represent this by setting flags on every
instance of those backends; it's just confusing and doesn't provide
more information. In other words, unchanging is only meaningful for
backends that normally dynamically generate new keys on get, like the
keytab backend.
Expiration
The database has a field to store an expiration date for every object.
We can implement expiration methods in the backend to automatically
destroy some objects (or perhaps lock them) when they pass their
expiration date, but a more useful method might be to provide warnings
when objects are about to expire via warning methods for a backend
that take the object name and the expiration date. This would be
great for certificates, for instance.
Not clear whether every get and store should check the expiration or
just a nightly cron job that blows away or locks objects when they
pass their expiration.
Keytab Backend
As of the deployment of the wallet, we want to stop limiting nearly
all keytabs from being forced to single DES keys. We're probably
still going to have some keys for which only particular enctypes are
permitted, however. This means keeping a side table of allowable
enctypes per keytab name, where if there are no entries in the table
we allow any enctype. We can pass a list of enctypes into kadmin when
doing the principal creation or randomization, separated by spaces and
enclosed in double quotes.
When creating a new principal with addprinc, pass the -clearpolicy
flag. Otherwise, the principal will be placed in the default policy
and will be subject to password strength checking, and the initial
password used with -randkey will fail.
Whenever we generate a new keytab, we may need to push the key into
K4. We could make the client send a flag saying whether they want
synchronization with K4, but it's easier to just always do it (except
maybe for some exception cases). The user doesn't have to ask the
client program for the srvtab if they don't want it, and it doesn't
hurt to create the KDC entry. We use kasetkey for this.
Certificate Creation
We probably want to handle all requested certificates from Comodo
using this interface since we can use its expiration handling to do
warnings and since that way users can re-download the certificate any
time they want. Certificates are actually pairs of certificate and
key, though, and we need to figure out what we're storing. There is
the key, which we want to be able to store but we don't really do
anything with (except ideally it's associated with a certificate),
there's the CSR (which we could reuse for renewals although that
doesn't get people to change their key), and there's the certificate
itself (which is actually public data).
People seem to like to have CSRs kept around, but I don't understand
why and need to investigate this further. It makes more sense to me
to generate a new key every time the cert is renewed, for additional
security.
We may be able to just store a file that contains both the key and the
public certificate and change our practices on web server
configuration to point them at the combined file.
Cleanup of Old Entries
We should periodically scan the wallet for host-based entries for hosts
that aren't in NetDB. Rather than removing them immediately, wait
until we haven't seen the host for several consecutive passes and then
purge them. Send notification of the hosts that are being purged (and
maybe of the hosts that will be purged soon if nothing happens),
although that raises the question of where to send the notification.
Client Issues
Command-Line Options
Some of the specific data types are going to need their own flags to
operations like get. As an example, the keytab get operation will
need an optional flag to specify the srvtab file to which to also
write the key, and will need an optional flag specifying the time
delta at which old kvnos should be pruned from the keytab. These
flags need to be globally unique in the wallet client so that we can
use a naive option parser. It would also be nice to support the flags
anywhere in the command and not go down the weird CVS route of flags
meaning different things in different places.
Keytab Handling
The server is going to hand the client a keytab that contains the
current keys for the given service. Unless the keytab was marked as
unchanging, these entries will have a higher kvno than any keys
already in the keytab on the local system.
The only interfaces to read keytabs require a file, so the client will
need to save the keytab to a temporary file in order to extract
individual keys. If there is no keytab on the local system in the
path given to the wallet, this is simple; just write the keytab as
returned by the server into the file.
If the keytab already exists, we want the following behavior:
* Add the keys from the new keytab.
* Retain in the keytab keys for the previous kvno, but not for any
older kvno older than the maximum lifetime of Kerberos tickets. So
scan the keytab for keys with an older kvno and a timestamp older
than one day (maybe make it a week just in case) and delete them.
(Possibly make this configurable.)
* Delete any keys in the keytab matching the current kvno, just to be
sure we don't get any strange issues.
We want to try to add the new keys first to minimize the outage window
where service tickets handed out by the KDC aren't recognized by the
host. Adding the keys does just append them to the end, but we
probably have to clean out any keys with the same kvno first. That's
a rare case, so I don't think we have to worry about the outage window
there.
Srvtab Handling
If a srvtab was requested, we search for the key in the new keytab
that has an enctype of ENCTYPE_DES_CBC_CRC and then write it out to a
srvtab file. The MIT Kerberos library doesn't support writable
srvtabs in the keytab backend, so we roll that ourselves.
Look at src/lib/krb5/keytab/kt_srvtab.c in the MIT Kerberos source for
the format of a srvtab file (see the end of that file).
The kvno that we get from K5 may have no bearing on the kvno in K4.
In order to get the K4 kvno, use the new key to obtain a K4 service
ticket for ourselves and then read the kvno off that service ticket.
There are other approaches, but the other approaches all require
changes to the server side as well, whereas this is self-contained in
the client and can be more easily dropped when we drop K4.
License
Copyright 2006, 2007, 2008, 2013
The Board of Trustees of the Leland Stanford Junior University
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without any warranty.
|