diff options
author | Russ Allbery <rra@stanford.edu> | 2007-03-08 23:57:40 +0000 |
---|---|---|
committer | Russ Allbery <rra@stanford.edu> | 2007-03-08 23:57:40 +0000 |
commit | 7d50b9887901466994b9fe3af4d79624959217ff (patch) | |
tree | d65be89771ea77f358d8de6b640b48161c82953d /docs | |
parent | a79cb00d2b7931bcdba0ff169437a78edfb8acf8 (diff) |
Rename to docs for compatibility with other packages.
Diffstat (limited to 'docs')
-rw-r--r-- | docs/design-acl | 90 | ||||
-rw-r--r-- | docs/design-api | 94 | ||||
-rw-r--r-- | docs/design-schema | 112 | ||||
-rw-r--r-- | docs/netdb-role-api | 32 | ||||
-rw-r--r-- | docs/notes | 223 |
5 files changed, 551 insertions, 0 deletions
diff --git a/docs/design-acl b/docs/design-acl new file mode 100644 index 0000000..cb07247 --- /dev/null +++ b/docs/design-acl @@ -0,0 +1,90 @@ + ACL Layer Design for the Wallet + +Introduction + + This is a description of the ACL layer of the wallet implementation. + This is a specification of the expected behavior of the ACL + implementation and includes the syntax and semantics of ACL strings + used in the database. The ACL strings used by the wallet are intended + to be an extensible format to which additional ACL backends may be + added as needed. When new ACL backends are added, they should be + described here. + +Syntax + + An ACL in the wallet consists of two pieces of data, a <scheme> and an + <instance>. <scheme> is one or more characters in the set [a-z0-9-] + that identifies the ACL backend to use when interpreting this ACL. + <identifier> is zero or more characters including all printable ASCII + characters except whitespace. Only the implementation of <scheme> + knows about the meaning of <identifier>. <identifier> may include + zero or more users. + +Semantics + + All users are authenticated to the wallet by Kerberos and are + therefore represented by a Kerberos principal, which follows the + normal Kerberos rules for string representation. + + Whenever there is a question about whether a user is permitted an + action by a particular ACL, the following verification algorithm is + used: Iterate through each ACL string on the ACL in question. If the + ACL string is malformatted or the scheme is not recognized, skip it. + Otherwise, dispatch the question to the check function of the ACL + implementation, passing it the principal identifying the client and + the <identifier> portion of the ACL string. This function returns + either authorized or unauthorized. If authorized, end the search; if + unauthorized, continue to the next ACL string. + + There is no support in this scheme for negative ACLs. + + There is one slight complication, namely that some ACL methods need to + maintain persistant state for performance reasons (consider, for + example, an ACL layer implemented with LDAP queries). Therefore, each + ACL handler should be represented by an object, and when the ACL code + discovers it doesn't already have an object on hand for a given ACL + scheme, it should construct one before querying it. If construction + fails, it should fail that scheme and any ACL that uses that scheme, + but still allow access if an ACL not using that scheme grants access + to the user. + +ACL Schemes + + krb5 + + The <identifier> is a fully-qualified Kerberos principal. Access is + granted if the principal of the client matches <identifier>. + + krb5-group + + <identifier> is the name of a group that contains a list of Kerberos + principals. (Storage of this group is left to the discretion of the + backend, but will probably either be a MySQL table or a file on disk.) + Access is granted if the principal of the client matches one of the + principals contained in the group. + + ldap-entitlement + + <identifier> is an entitlement. If the entitlement attribute of the + LDAP entry corresponding to the given principal contains the + entitlement specified in <identifier>, access is granted. + + netdb + + This ACL type is a special case that right now can't be used through + the normal ACL mechanism because access depends on the name of the + object being accessed through logic peculiar to the backend. It is + included here as a placeholder, but will normally only be used via the + backend-specific fallback used when the ACL is not present. + + Access is granted if the action performed is one of the normal owner + actions, the object being accessed corresponds to a system key, and + the user is an administrator of that system in NetDB (Stanford's + system management database). + + For this ACL, <identifier> is empty. + + pts + + <identifier> is the name of an AFS PTS group. Access is granted if + the principal of the user is a member of that AFS PTS group. diff --git a/docs/design-api b/docs/design-api new file mode 100644 index 0000000..0af6862 --- /dev/null +++ b/docs/design-api @@ -0,0 +1,94 @@ + Wallet Server API + +Introduction + + Here is the specification for the API that components of the wallet + server will implement. There are two pluggable components in the + wallet server: the implementation of a particular object type (which + amounts mostly to storage and retrieval), and the ACL implementation. + +Object API + + new(NAME, DBH) + + Creates a new object with the given object name. Takes a database + handle, which should be stored with the object and used for any + further operations. This method should inherit from the generic + Wallet::Object object, which implements the following methods: + + new(NAME, DBH) + create(NAME, DBH) + owner([ACL-ID]) + acl(TYPE [, ACL-ID]) + expires([DATETIME]) + get(PRINCIPAL, HOSTNAME [, DATETIME]) + store(DATA, PRINCIPAL, HOSTNAME [, DATETIME]) + show() + error() + + that manipulate the basic object data. Generally all this function + needs to do is call the parent new() constructor, but if there are + additional database tables used by this object type, it may load + additional data. + + create(NAME, DBH, PRINCIPAL, HOSTNAME [, DATETIME]) + + Like new(), but instead creates a new entry in the database with the + given name. As with new(), the generic function will normally do all + of the work. Takes some additional information to put into the + created fields in the database. + + get(PRINCIPAL, HOSTNAME [, DATETIME]) + + Applied to a returned object, retrieves the data contained in the + object in question. Takes the information about who is doing the + retrieval so that the database metadata can be updated. The result is + either the relevant data or undef in the event of an error. On error, + the caller should call error() to get the error text. + + store(DATA, PRINCIPAL, HOSTNAME [, DATETIME]) + + Store user-supplied data into the given object. This may not be + supported by all backends (for instance, backends that automatically + generate the data will not support this). Takes the information about + who is doing the store so that the database metadata can be updated. + The result is true on success and false on failure. On error, the + caller should call error() to get the error text. + + show() + + Returns a formatted text description of the object suitable for human + display, or undef on error. On error, the caller should call error() + to get the error text. + + default_check(PRINCIPAL) + + Applies the default authorization rules for this object type, if any, + and returns 1 if those default authorization rules allow access. If + there are no authorization rules or if they don't allow access, + returns 0. On error, returns undef; the caller should call error() to + get the error text. + + error() + + Returns the error text from the last failed get(), store(), show(), or + default_check() call. + +ACL API + + new() + + Creates a persistant ACL verifier for the given ACL type. This may do + nothing, but some ACL verifiers require some persistant data, like a + persistant LDAP connection. + + check(PRINCIPAL, ACL) + + Checks whether the given PRINCIPAL should be allowed access given ACL. + Returns 1 if access is granted, 0 if access is declined, and undef on + error. On error, the caller should call error() to get the error text + but generally should continue with checking other ACLs. + + error() + + Returns the error text of the last error. diff --git a/docs/design-schema b/docs/design-schema new file mode 100644 index 0000000..c82c387 --- /dev/null +++ b/docs/design-schema @@ -0,0 +1,112 @@ + Database Schema for the Wallet + +Introduction + + Here should be a comprehensive list of the tables used by the wallet, + the SQL to create those tables, and a specification of what they're + for. It's possible that this file will later be written in some other + format to make extraction of the SQL easier. Please do not copy this + data into some other file that could get out of sync with this + documentation; instead, if it's necessary to change the format, please + move this file elsewhere and keep the documentation with the schema. + +Object Metadata + + Each object stored in the wallet is represented by an entry in the + objects table: + + create table objects + (ob_name varchar(255) not null, + ob_type varchar(16) + not null references types(ty_name), + ob_owner integer default null references acls(ac_id), + ob_acl_get integer default null references acls(ac_id), + ob_acl_store integer default null references acls(ac_id), + ob_acl_show integer default null references acls(ac_id), + ob_acl_delete integer default null references acls(ac_id), + ob_acl_flags integer default null references acls(ac_id), + ob_expires datetime, + ob_created_by varchar(255) not null, + ob_created_from varchar(255) not null, + ob_created_on datetime not null, + ob_stored_by varchar(255), + ob_stored_from varchar(255), + ob_stored_on datetime, + ob_downloaded_by varchar(255), + ob_downloaded_from varchar(255), + ob_downloaded_on datetime, + primary key (ob_name, ob_type)); + + Object names are not globally unique but only unique within their + type, so the table has a joint primary key. I haven't yet decided + what indices the table will need. + + Each object has an owner and then up to five more specific ACLs. The + ob_acl_flags ACL controls who can set flags on this object. Each ACL + references entries in the following table: + + create table acls + (ac_id integer auto_increment primary key); + + This just keeps track of unique ACL identifiers. The data is then + stored in: + + create table acl_entry + (ae_id integer not null references acls(ac_id), + ae_scheme varchar(32) + not null references acl_schemes(as_name), + ae_identifier varchar(255)); + + Finally, each object may have zero or more flags associated with it. + + create table flags + (fl_object varchar(255) + not null references objects(ob_name), + fl_type varchar(16) + not null references objects(ob_type), + fl_flag varchar(32) + not null references flag_names(fn_name)); + + The following are normalization tables used to constrain the values + + create table types + (ty_name varchar(16) primary key); + + create table acl_schemes + (as_name varchar(32) primary key); + + create table flag_names + (fn_name varchar(32) primary key); + +ACL Backend Data + + To support the krb5-group ACL type, groups are stored in the following + table: + + create table krb5_groups + (kg_name varchar(255) primary key, + kg_owner integer default null references acls(ac_id)); + + Each group contains zero or more principals: + + create table krb5_members + (km_group varchar(255) + not null references krb5_groups(kg_name), + km_principal varchar(255) not null); + +Storage Backend Data + + To support restricting the allowable enctypes for a given keytab, the + keytab backend will use the following table: + + create table keytab_enctypes + (ke_principal varchar(255) + not null references objects(ob_name), + ke_enctype varchar(255) + not null references enctypes(en_name)); + + There is a normalization table to ensure that only supported enctypes + are configured: + + create table enctypes + (en_name varchar(255) primary key); diff --git a/docs/netdb-role-api b/docs/netdb-role-api new file mode 100644 index 0000000..6dbcfa4 --- /dev/null +++ b/docs/netdb-role-api @@ -0,0 +1,32 @@ + NetDB Role API + +Basic API + + remctl netdb-node-roles-rc netdb node-roles <sunetid> <node> + + Note that the remctl principal used here is actually the underlying + host principal, not the principal for that alias. <node> must be + fully qualified. This will return a list of all roles that <sunetid> + has with <node>, chosen from admin, team, or user. For our purposes, + we probably want to look at admin and team, but we may want user as + well. + + You must be a current NetDB user to use it. It just sucks rows out of + a view matching on the SUNet ID and node name, so getting no result + can mean "no such SUNet ID," "no such node," or "SUNet ID isn't + associated with node." + +Examples + + % remctl netdb-node-roles-rc netdb node-roles riepel zathras.stanford.edu + admin + team + user + % remctl netdb-node-roles-rc netdb node-roles riepel calgon.stanford.edu + admin + % + +Wallet Issues + + We'll need to get a principal registered to use it that can query + anything for any node but isn't otherwise authorized to use NetDB. diff --git a/docs/notes b/docs/notes new file mode 100644 index 0000000..eaa6e5b --- /dev/null +++ b/docs/notes @@ -0,0 +1,223 @@ + 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 not user documentation or protocol specifications; see elsewhere + for that. + +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 unchanging + flag -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 (triggered by a get or + store of something that didn't already exist), delete, 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. There does need to + be an ACL on create, but that should probably be implemented per + backend class (keytabs and certs will use NetDB roles, files will use + some namespace limitation based on a separate table, etc.). There may + also need to be a class-specific fallback when no ACL is set to deal + with, for instance, ACL management via NetDB roles for systems that + have no more specific ACL. + + Owner rights provides get, store, and show, but not delete or setting + or clearing flags (not delete because it's too destructive and we + don't want it done accidentally). This can be overridden by more + precise ACL settings. So the ACL logic would go like this: + + * If the user is an administrator, 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, or show, apply the owner ACL. + + * If there is no listed owner ACL, punt to the backend and see if it + can apply a default ACL. + + * If the object doesn't exist, punt to the backend, which will do its + own ACL check against backend-specific rules. + + I think the owner abstraction is worth it over just setting the ACL + for get, store, and show. + + We also need to provide an interface to manage certain types of ACLs, + in particular the krb5-group ACL scheme, at least in the short term + until we standardize on using LDAP for all of those ACLs. We're + probably going to continue to use krb5-group ACLs for the forseeable + future in at least some cases, since we'll want to be able to do + things when LDAP or AFS is down or we'll want a higher level of + security than either can ensure. + + 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. + + Expiration + + The database has a field to store an expiration date for every object. + We can implement expiration methods in the backend to automatically + delete 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. + + 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. + + This means that we need the gen_srvtab program from the old srvtab + backend on the server end to push the key into K4. That program + already has the capability to take a srvtab containing the DES key and + push it into the K4 database. It could probably stand some cleanup + and simplification for inclusion in the wallet source. I'm probably + going to rename it to k4changekey or something similar in the process. + + 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). Should there be some method + for someone to request that their previous CSR be reused to request a + new Comodo certificate? Maybe more work than needed. + + 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). + +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, although at least for starters we'll + probably require that all the options be given after the operation. + + 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. |