Difference between revisions of "RackTablesAdminGuide"

From RackTables Wiki
Jump to navigation Jump to search
(another RackCode example)
(merging Craig Hoffman's page found in backup)
Line 224: Line 224:
 
allow {HQ admins} and ({HQ assets} or {HQ managed})
 
allow {HQ admins} and ({HQ assets} or {HQ managed})
 
</pre>
 
</pre>
 +
 +
= Defining a new RackTables Object Type =
 +
(contributed by Craig Hoffman)
 +
 +
Perhaps you have a piece of equipment that is currently not listed in the default list of RackTables objects. This could be something physical, like an environmental sensor. Or, perhaps, you want to extend RackTables to support something more virtual, like network circuits. (RackTables is probably not the best utilized in this "virtual object" manner. RackTables is designed for '''Objects''' in a '''Rack'''. That being said, I wanted to have my CircuitDB info in one location. To this end, I created a Rack Row called "Virtual", and a 47U rack called "Circuits". I just stick each of my circuits in there so they don't show up as "Un Mounted".)
 +
 +
This process has been discussed from time to time on the mailing list.  Here's how you do it:
 +
 +
* From the Main Menu, select Configuration, Dictionary, and then select the dictionary "RackObjectType".
 +
* Select "Edit" and add the new object type that you wish to create.  I extended RackTables to support circuits, so I typed in "Circuit".
 +
Now you need to create a dictionary entry that will be used to tie attributes to.
 +
* From the Main Menu, select Configuration, Dictionary, and then select "Manage Chapters" at the top. Add a new entry (Circuit ID as my example).
 +
You can now create the attributes that will be assigned to your new dictionary entry.  For a circuit, things like circuit ID#, carrier, AS#, contact name, etc.  You can always go back and add more attributes as needed.
 +
* From the Main Menu, select Configuration, Attributes, and Edit Attributes.  Create each attribute that you need.  Take care in the '''type''' of attribute.  "String" is probably what you want, when in doubt. 
 +
You're just about done.  It's time to assign those new attributes to the dictionary entry. 
 +
* From the Main Menu, select Configuration, Attributes, and Edit Map.  Select the new attributes and apply it to the new dictionary entry.  You probably do not need to do anything with the third dropdown box, "dictionary chapter...".
 +
 +
Now you should be able to go back to the Main Menu, and create some new objects with your new Object Type.

Revision as of 12:23, 30 March 2010

User authentication

Authentication is a way to tell, that the remote user is who he pretends to be. This can be done in three ways with or without knowing user's password. This is controlled through an option on the configuration page. User accounts must exist and have necessary permissions assigned in !RackTables database. !RackTables traditional account locking works regardless of authentication sources, so one can always disable accounts one by one, if necessary.

Local authentication

This is the oldest (and default) method. Password hashes are stored in SQL database along with all other data. !RackTables checks the passwords itself.

LDAP authentication since (version 0.14.10+)

Administrator user is the user with user_id 1, in the default installation his username is "admin". Administrator user is always authenticated locally via the accounts database. Other user accounts are treated the same way by default, but this can be changed. There are two steps to start using LDAP authentication:

  • Make sure there is a working LDAP environment already. phpLDAPadmin is a very helpful tool for that.
  • Set necessary LDAP authentication options in {{{$LDAP_options}}} array in {{{secret.php}}} file, as described below.

Single LDAP server

$LDAP_options['server'] = 'server.yourcompany.com';

Multiple LDAP servers

Should work, according to a user's comment on PHP manual page:

Note that hostname can be a space-separated list of LDAP host names. This is very useful for failover; if the first ldap host is down, ldap_connect will ask the second LDAP host and so on.
$LDAP_options['server'] = 'server1.yourcompany.com server2.yourcompany.com server3.yourcompany.com';

with domain: Active Directory

There are two pieces: username and domain. You set the domain once:

$LDAP_options['domain'] = 'ad.yourcompany.com';

Each user types in his own username. Both parts are internally joined together and used to perform the actual authentication, e.g. "user@ad.yourcompany.com". That's simple, because everyone has unique username. This doesn't scale well.

with search: OpenLDAP and others

There are often many nested organizational units (OUs) within one organization (O). Traditional LDAP implementations let each OU have its own list of usernames, so that some usernames are only unique within given OU. To keep things working and tell who is who, the following approach is used. The users with globally unique usernames type in their username. Others know, that they have to use their UID instead. LDAP database is maintaned so, that UID is a little longer, than username, but yet unique. To map presented UID into common name (CN, which is the canonical, long form of user's identifier) LDAP search is performed. All this works automatically, once you specify the search DN and search attribute:

$LDAP_options['search_dn'] = 'ou=people,O=YourCompany';
$LDAP_options['search_attr'] = 'uid';

final adjustments

This setting makes !RackTables really look into $LDAP_options. Note that if your configuration doesn't work, you can quickly revert to local password check by simple commenting that line out.

$user_auth_src = 'ldap';

Another option makes !RackTables satisfied by an account existing in LDAP. By default a user is required to be listed in the list of local accounts, even if his password was verified by LDAP server.

$require_local_account = FALSE;

LDAP search feature was contributed by Walery Wysotsky and available since release 0.16.2. Since 0.17.0 LDAP options are stored in $LDAP_options array.

external authentication (since 0.17.0)

In this mode !RackTables only makes sure, that the user is using a username to access. It is assumed, that Apache is configured to authenticate users, like:

AuthType basic
AuthName "beware ogres"
AuthUserFile /var/www/racktables/.htpasswd
Require valid-user

After Apache configuration it is necessary to open !RackTables main page and make sure, that Apache really blocks unauthenticated users, whichever means it uses to validate them (htpasswd, LDAP, Kerberos and so on). Only after that the software configuration must be changed to always trust the username provided (because the web-server has already validated it). This is done in secret.php file:

$user_auth_src = 'httpd';

logging out

When using external user authentication, special care should be taken to enable logging out of the system. According to HTTP spec, user agent (browser) among other factors uses "authentication realm" to decide, which username and password to send, when requesting each page. When the browser gets HTTP code 401 ("unauthorized"), it resets cached username/password pair for the realm, which is presented in the 401 reply. The "logout" link in !RackTables points to a special location, which always refuses to authenticate, and presents the same realm, which was used for initial authentication. That works fine for local and LDAP authentication, because in both cases the realm comes from the same source. For "httpd" authentication, however, this isn't always true (realms mismatch and cached password isn't reset), so a user often cannot log out by following "logout" link.

To make things working again, it is necessary to make the realm, which Apache presents to the user, match the one, which is seen after following the "logout" link. Let's suppose, you see {{{Snake Oil RackTables access-500}}} after clicking "logout" (500 or other value is often added by Apache PHP module to make things more secure). The setting in htaccess file then should be:

AuthName "Snake Oil RackTables access-500"

After that it's easy to find, that logging out works again.

Resetting administrator password (and username)

mysql> UPDATE UserAccount SET user_name = 'admin', user_password_hash = SHA1('mynewpassword') where user_id = 1;

Troubleshooting LDAP Authentication

From Mailing list post

OpenLDAP:

You may run into an issue where !RackTables is unable to authenticate against OpenLDAP. Try this:

Run openldap with "slapd -d 16380".

If you see an error similar to:

send_ldap_result: err=2 matched="" text="historical protocol version requested, use LDAPv3 instead" 

Try this near the top of slapd.conf

# Global Directives:
allow bind_v2

Failover setup

RackTables' purpose is to aid in troubleshooting, but sometimes the problem makes !RackTables system unavailable itself. A read-only backup replica of the server will help making through the accident faster. The diagram below explains necessary setup:

RackTables-failover.png


Vendor sieve (since 0.17.0)

The dictionary is made of many (hundreds) records, most of them being hardware models. The records are usually grouped by OEM brand or product line. It's common to stick with one particular brand and never purchase others. However, by default all records are shown in drop-down SELECT lists on "Properties" tab of each object. It is possible to hide certain option groups from being rendered by default. To do so, navigate to "Configuration", then to "User interface" and switch to "Change". There is an option (empty by default) named "Vendor sieve configuration". Its format is:

Vendor1; Vendor2@X; Vendor3; Vendor4@Y; ...

Here VendorZ is what you see in bold in drop-down list (OPTGROUP, to be specific), and X/Y are optional numeric values of object type. If the object type isn't specified, related vendor is screened out from SELECTs for all object types. So, say, one has Sun (tm) tape libraries, but has no Sun (tm) servers. To hide "Sun" OPTGROUP from the list of server models and leave it on the list of tape libraries, he puts the following into option value:

Sun@4

This way the "HW type" SELECT gets considerably shorter. However, this feature is purely cosmetic: it doesn't remove any data from the SQL database, and doesn't change existing data. If there is a particular server marked as one of Sun (tm) boxes, the record is shown as before and upon going to "Properties" tab the whole "Sun" OPTGROUP is there (because the value is already set). It's possible to change from one Sun model to another in this situation. But once the box is changed to, say, a noname server, the "Sun" OPTGROUP is again gone, as requested by the sieve.


AutoPorts

When we create objects, we often (if not always) add some ports to them depending on the type and hardware model. Although !RackTables can't yet add ports depending on hardware model (except via SNMP), it is (as of 0.14.12 release) able to automatically add ports upon object creation. This process is controlled by !AutoPorts configuration string:

<object type1 id>=<n1>*<port type1 id>*<format1>;<object type2 id>=<n2>*<port type2 id>*<format2>+<n3>*<port type3 id>*<format3>;<object type3 id>=<n4>*<port type4 id>*<format4>+<n5>*<port type5 id>*<format5>...

The default value is "{{{4 = 1*33*kvm + 2*24*eth%u}}}", which makes each new server to have 2 Linux-style GigE ports and 1 KVM port. To make each new PDU bear 6 power plugs in addition to this, the !AutoPorts config would be as follows: "4 = 1*33*kvm + 2*24*eth%u; 2 = 6*16*%02u". Exact key values can be found on the dictionary page in chapters !PortType and !RackObjectType (keys are rendered as mouse hints for each dictionary record). The format string is the one accepted by printf family functions and ports are indexed starting from 0 and upwards.

The feature can also make its work later. When you browse an object, which has no ports yet, but could have (according to !AutoPorst configuration), you see additional tab named "!AutoPorts". It will present you with its idea of which records could be added, and a button to do so. Once you add any ports to an object by automatic or manual mean, the tab will hide itself.


Live VLANs

RackTables can be used to ease access switches management by presenting a user with current VLAN membership for each switch port and letting him change the configuration and submit for instant activation. This functionality was implemented through a "gateway" for Cisco devices with an intention to add more vendor support later. Configuration consists of several steps:

  1. Pick a [Cisco Catalyst] switch and set its hardware and software types in Properties. This will trigger the "Live VLANs" tab to appear for this object.
  2. Decide on the so called "endpoint", which will be used to connect to the device. The safest approach is to have FQDN sticker set for each switch. However, if you always have one (and only one) IP address listed for each managed switch, you can omit setting FQDN, because the IP address will be used. Furthermore, if you don't list IPv4 allocations at all (not a good idea), object's common name is the last resort for the endpoint. If more than 1 IP address is listed, FQDN is a mandatory attribute to set.
  3. Change to the gateways/switchvlans directory and prepare gateway's own configuration files. The syntax should be straightforward, it isn't the best possible, but it lets configure things.
$ cp cisco.secrets.php-sample cisco.secrets.php
$ cp userauth.php-sample userauth.php
$ touch changes.log
$ chmod 666 changes.log # to keep track of changes
$ vi cisco.secrets.php userauth.php
  1. Get back to browser, click the Live VLANs tab and enjoy.

KVM ports

Since the 0.14.11 release RackTables has 2 distinct port types for physical console: "KVM (host)" and "KVM (console)". Both types more describe the function, than an exact set of connectors. The former one emits video signal and accepts keyboard and/or mice events. The latter one accepts video signal and emits HID events. There's no specification, which mix of DVI, DB15, PS/2, DIN, USB and even Sun connectors is in question for each particular port, hence a variety of cabling and convertors is usually available. One usually just has "console" or "KVM switch" boxes with "KVM (console)" ports and server boxes with "KVM (host)" ports. Then connecting two servers or two pure consoles together wouldn't be possible, as it used to be before.

A known drawback of the new approach is that all the ports (especially connected ones), which were created before the 0.14.11 release, now belong to "KVM (host)" type regardless of their actual function. There are ways to fix this depending on the number of such ports:

  • Small: delete and re-add ports manually.
  • Average: issue UPDATE SQL statement (backup you data first!).
  • Really big: ask for help on the racktables-users mailing list. We might invent an automatic upgrading script.

Fixing the RackCode

It's possible to write RackCode, which locks you out, so you can't fix things the usual way. In most situations you can always log in as administrator and fix things, but it's possible to break even this. The following SQL code restores administrator access:

update Script set script_text = NULL where script_name = 'RackCodeCache';
update Script set script_text = concat('allow {$userid_1} ', script_text) where script_name = 'RackCode';

Permission configuration examples

Administrator with unlimited access

allow {$userid_1} # admin is always UID 1 regardless of username

Admin and power user

allow {$userid_1}
allow {$username_jack}

Admin and a group of power users

This approach requires creating a tag (Configuration -> Tag tree) named "power user". Then each user account of the group must be tagged with this tag. After that the following code text would do the trick:

allow {$userid_1}
allow {power user}

This way it's possible to run with the same text, granting and revoking permissions through attaching and removing role tags.

Admin, a group of power users and a group of managers

RackTables pages have tabs. There is always at least one tab, the "default" one. Its name is always "default" and its contents doesn't allow changing things. It may show data about current items and/or links to other pages, but basically it's read-only. This way, having {$tab_default} on the current security context is equivalent to read-only access. Of course, this setup assumes a role tag for managers accounts.

allow {$userid_1} or {power user}
allow {manager} and {$tab_default}

Admin can write, anyone can read

allow {$userid_1} or {$tab_default}

Permitting a user to view his own assets

Let's suppose you are setting up !RackTables for a colocation provider. A customer company, Snake Oil Web Services, wants to see what happened to their 20 servers you have accepted for colocation. They would also like to know which server must use which IP address for things to work. You create a user account, "snakeoil", then create a tag "Snake Oil asset" and use it to tag each of that 20 servers. After that the following code permits them what they need and nothing else:

allow {$username_snakeoil} and {$tab_default} and {Snake Oil asset}

There are things to mention, which aren't obvious:

  1. The user will be able to access only the pages, which display objects. As long as you use "Snake Oil asset" tag to mark servers only, it will get onto the context only in specific locations. IOW, the "snakeoil" account will not be authorized to view even the main page. For this specific case you can provide them with a list of 20 URLs.
  2. When you decide to use a more generic description for the tag, it becomes easy to achieve unexpected results with valid permission rules. Say, if you have a "Snake Oil" tag, some hardware and several user accounts, you may decide to tag not only servers, but accounts as well. This will effectively permit every Snake Oil account to access default tab of every page in the system, because of {Snake Oil} being always present on the security context. That's why the example uses {Snake Oil asset} to help things remain separated.

Headquarters and branch offices

Let's assume having the follwing tag tree:

- assets
-- HQ assets
-- HQ managed
-- Arizona assets
-- Texas assets
- admins
-- HQ admins
-- Arizona admins
-- Texas admins

Then the following ruleset would allow each branch viewing all, but managing only own assets. Some local stuff could be placed under authority of the headquarters (this stuff would be tagged with 2 tags at a time).

allow {admins} and {assets} and {$tab_default}
deny not {HQ admins} and {HQ managed}
allow {Arizona admins} and {Arizona assets}
allow {Texas admins} and {Texas assets}
allow {HQ admins} and ({HQ assets} or {HQ managed})

Defining a new RackTables Object Type

(contributed by Craig Hoffman)

Perhaps you have a piece of equipment that is currently not listed in the default list of RackTables objects. This could be something physical, like an environmental sensor. Or, perhaps, you want to extend RackTables to support something more virtual, like network circuits. (RackTables is probably not the best utilized in this "virtual object" manner. RackTables is designed for Objects in a Rack. That being said, I wanted to have my CircuitDB info in one location. To this end, I created a Rack Row called "Virtual", and a 47U rack called "Circuits". I just stick each of my circuits in there so they don't show up as "Un Mounted".)

This process has been discussed from time to time on the mailing list. Here's how you do it:

  • From the Main Menu, select Configuration, Dictionary, and then select the dictionary "RackObjectType".
  • Select "Edit" and add the new object type that you wish to create. I extended RackTables to support circuits, so I typed in "Circuit".

Now you need to create a dictionary entry that will be used to tie attributes to.

  • From the Main Menu, select Configuration, Dictionary, and then select "Manage Chapters" at the top. Add a new entry (Circuit ID as my example).

You can now create the attributes that will be assigned to your new dictionary entry. For a circuit, things like circuit ID#, carrier, AS#, contact name, etc. You can always go back and add more attributes as needed.

  • From the Main Menu, select Configuration, Attributes, and Edit Attributes. Create each attribute that you need. Take care in the type of attribute. "String" is probably what you want, when in doubt.

You're just about done. It's time to assign those new attributes to the dictionary entry.

  • From the Main Menu, select Configuration, Attributes, and Edit Map. Select the new attributes and apply it to the new dictionary entry. You probably do not need to do anything with the third dropdown box, "dictionary chapter...".

Now you should be able to go back to the Main Menu, and create some new objects with your new Object Type.