Auth Documentation

Nova provides RBAC (Role-based access control) of the AWS-type APIs. We define the following roles:

Roles-Based Access Control of AWS-style APIs using SAML Assertions “Achieving FIPS 199 Moderate certification of a hybrid cloud environment using CloudAudit and declarative C.I.A. classifications”

Introduction

We will investigate one method for integrating an AWS-style API with US eAuthentication-compatible federated authentication systems, to achieve access controls and limits based on traditional operational roles. Additionally, we will look at how combining this approach, with an implementation of the CloudAudit APIs, will allow us to achieve a certification under FIPS 199 Moderate classification for a hybrid cloud environment.

Relationship of US eAuth to RBAC

Typical implementations of US eAuth authentication systems are structured as follows:

[ MS Active Directory or other federated LDAP user store ]
      --> backends to…
[ SUN Identity Manager or other SAML Policy Controller ]
      --> maps URLs to groups…
[ Apache Policy Agent in front of eAuth-secured Web Application ]

In more ideal implementations, the remainder of the application-specific account information is stored either in extended schema on the LDAP server itself, via the use of a translucent LDAP proxy, or in an independent datastore keyed off of the UID provided via SAML assertion.

Basic AWS API call structure

AWS API calls are traditionally secured via Access and Secret Keys, which are used to sign API calls, along with traditional timestamps to prevent replay attacks. The APIs can be logically grouped into sets that align with five typical roles:

  • System User
  • System Administrator
  • Network Administrator
  • Project Manager
  • Cloud Administrator
  • (IT-Sec?)

There is an additional, conceptual end-user that may or may not have API access:

  • (EXTERNAL) End-user / Third-party User

Basic operations are available to any System User:

  • Launch Instance
  • Terminate Instance (their own)
  • Create keypair
  • Delete keypair
  • Create, Upload, Delete: Buckets and Keys (Object Store) – their own
  • Create, Attach, Delete Volume (Block Store) – their own

System Administrators:

  • Register/Unregister Machine Image (project-wide)
  • Change Machine Image properties (public / private)
  • Request / Review CloudAudit Scans

Network Administrator:

  • Change Firewall Rules, define Security Groups
  • Allocate, Associate, Deassociate Public IP addresses

Project Manager:

  • Launch and Terminate Instances (project-wide)
  • CRUD of Object and Block store (project-wide)

Cloud Administrator:

  • Register / Unregister Kernel and Ramdisk Images
  • Register / Unregister Machine Image (any)

Enhancements

  • SAML Token passing
  • REST interfaces
  • SOAP interfaces

Wrapping the SAML token into the API calls. Then store the UID (fetched via backchannel) into the instance metadata, providing end-to-end auditability of ownership and responsibility, without PII.

CloudAudit APIs

  • Request formats
  • Response formats
  • Stateless asynchronous queries

CloudAudit queries may spawn long-running processes (similar to launching instances, etc.) They need to return a ReservationId in the same fashion, which can be returned in further queries for updates. RBAC of CloudAudit API calls is critical, since detailed system information is a system vulnerability.

Type declarations

  • Data declarations – Volumes and Objects
  • System declarations – Instances

Existing API calls to launch instances specific a single, combined “type” flag. We propose to extend this with three additional type declarations, mapping to the “Confidentiality, Integrity, Availability” classifications of FIPS 199. An example API call would look like:

RunInstances type=m1.large number=1 secgroup=default key=mykey confidentiality=low integrity=low availability=low

These additional parameters would also apply to creation of block storage volumes (along with the existing parameter of ‘size’), and creation of object storage ‘buckets’. (C.I.A. classifications on a bucket would be inherited by the keys within this bucket.)

Request Brokering

  • Cloud Interop
  • IMF Registration / PubSub
  • Digital C&A

Establishing declarative semantics for individual API calls will allow the cloud environment to seamlessly proxy these API calls to external, third-party vendors – when the requested CIA levels match.

See related work within the Infrastructure 2.0 working group for more information on how the IMF Metadata specification could be utilized to manage registration of these vendors and their C&A credentials.

Dirty Cloud – Hybrid Data Centers

  • CloudAudit bridge interfaces
  • Anything in the ARP table

A hybrid cloud environment provides dedicated, potentially co-located physical hardware with a network interconnect to the project or users’ cloud virtual network.

This interconnect is typically a bridged VPN connection. Any machines that can be bridged into a hybrid environment in this fashion (at Layer 2) must implement a minimum version of the CloudAudit spec, such that they can be queried to provide a complete picture of the IT-sec runtime environment.

Network discovery protocols (ARP, CDP) can be applied in this case, and existing protocols (SNMP location data, DNS LOC records) overloaded to provide CloudAudit information.

The Details

  • Preliminary Roles Definitions
  • Categorization of available API calls
  • SAML assertion vocabulary

System limits

The following limits need to be defined and enforced:

  • Total number of instances allowed (user / project)
  • Total number of instances, per instance type (user / project)
  • Total number of volumes (user / project)
  • Maximum size of volume
  • Cumulative size of all volumes
  • Total use of object storage (GB)
  • Total number of Public IPs

Further Challenges

  • Prioritization of users / jobs in shared computing environments
  • Incident response planning
  • Limit launch of instances to specific security groups based on AMI
  • Store AMIs in LDAP for added property control

The rbac Module

nova.auth.rbac.allow(*roles)
nova.auth.rbac.deny(*roles)

The signer Module

Utility class for parsing signed AMI manifests.

class nova.auth.signer.Signer(secret_key)

Bases: object

hacked up code from boto/connection.py

generate(params, verb, server_string, path)

The users Module

Nova users and user management, including RBAC hooks.

class nova.auth.users.AuthBase

Bases: object

classmethod safe_id(obj)

Safe get object id.

This method will return the id of the object if the object is of this class, otherwise it will return the original object. This allows methods to accept objects or ids as paramaters.

class nova.auth.users.Group(id, description=None, member_ids=None)

Bases: nova.auth.users.AuthBase

id and name are currently the same

has_member(user)
class nova.auth.users.KeyPair(id, owner_id, public_key, fingerprint)

Bases: nova.auth.users.AuthBase

delete()
class nova.auth.users.LDAPWrapper

Bases: object

add_role(uid, role, project_id=None)
add_to_group(uid, group_dn)
add_to_project(uid, project_id)
connect()
connect to ldap as admin user
create_key_pair(uid, key_name, public_key, fingerprint)
create’s a public key in the directory underneath the user
create_project(name, manager_uid, description=None, member_uids=None)
create_user(name, access_key, secret_key, is_admin)
delete_group(group_dn)
delete_key_pair(uid, key_name)
delete_key_pairs(uid)
delete_project(name)
delete_roles(project_dn)
delete_user(uid)
find_dns(dn, query=None)
find_group(dn)
uses dn directly instead of custructing it from name
find_group_dns_with_member(tree, uid)
find_key_pair(uid, key_name)
find_key_pairs(uid)
find_object(dn, query=None)
find_objects(dn, query=None)
find_project(name)
find_projects()
find_roles(tree)
find_user(uid)
find_user_by_access_key(access)
find_users()
group_exists(dn)
has_role(uid, role, project_id=None)
is_in_group(uid, group_dn)
is_in_project(uid, project_id)
key_pair_exists(uid, key_name)
project_exists(name)
remove_from_all(uid)
remove_from_group(uid, group_dn)
remove_from_project(uid, project_id)
remove_role(uid, role, project_id=None)
user_exists(name)
exception nova.auth.users.NoMorePorts(message=None)
Bases: nova.exception.Error
class nova.auth.users.Project(id, project_manager_id, description, member_ids)

Bases: nova.auth.users.Group

add_role(user, role)
generate_x509_cert(user)
get_credentials(user)
has_manager(user)
has_role(user, role)
project_manager
remove_role(user, role)
vpn_ip
vpn_port
class nova.auth.users.User(id, name, access, secret, admin)

Bases: nova.auth.users.AuthBase

id and name are currently the same

add_role(role)
create_key_pair(name, public_key, fingerprint)
delete_key_pair(name)
generate_key_pair(name)
generate_rc(project=None)
get_key_pair(name)
get_key_pairs()
has_role(role)
is_admin()
allows user to see objects from all projects
is_project_manager(project)
is_project_member(project)
is_superuser()
allows user to bypass rbac completely
remove_role(role)
class nova.auth.users.UserManager

Bases: object

add_role(user, role, project=None)
add_to_project(user, project)
authenticate(access, signature, params, verb='GET', server_string='127.0.0.1:8773', path='/', verify_signature=True)
create_key_pair(user, key_name, public_key, fingerprint)
create_project(name, manager_user, description=None, member_users=None)
create_user(user, access=None, secret=None, admin=False, create_project=True)
delete_key_pair(user, key_name)
delete_project(project)
delete_user(user, delete_project=True)
generate_key_pair(user, key_name)
generate_x509_cert(user, project)
get_key_pair(user, key_name)
get_key_pairs(user)
get_project(project)
get_projects()
get_user(uid)
get_user_from_access_key(access_key)
get_users()
has_role(user, role, project=None)
classmethod instance()
is_project_manager(user, project)
is_project_member(user, project)
remove_from_project(user, project)
remove_role(user, role, project=None)
class nova.auth.users.Vpn(project_id)

Bases: nova.datastore.BasicModel

classmethod create(project_id)
destroy()
classmethod find_free_port_for_ip(ip)
identifier
ip
classmethod num_ports_for_ip(ip)
port
save()

The users_unittest Module

class nova.tests.users_unittest.UserTestCase(methodName='runTest')

Bases: nova.test.BaseTestCase

setUp()
test_001_can_create_users()
test_002_can_get_user()
test_003_can_retreive_properties()
test_004_signature_is_valid()
test_005_can_get_credentials()
test_006_test_key_storage()
test_007_test_key_generation()
test_008_can_list_key_pairs()
test_009_can_delete_key_pair()
test_010_can_list_users()
test_101_can_add_user_role()
test_199_can_remove_user_role()
test_201_can_create_project()
test_202_user1_is_project_member()
test_203_user2_is_not_project_member()
test_204_user1_is_project_manager()
test_205_user2_is_not_project_manager()
test_206_can_add_user_to_project()
test_208_can_remove_user_from_project()
test_209_can_generate_x509()
test_210_can_add_project_role()
test_211_can_remove_project_role()
test_212_vpn_ip_and_port_looks_valid()
test_213_too_many_vpns()
test_299_can_delete_project()
test_999_can_delete_users()

The access_unittest Module

class nova.tests.access_unittest.AccessTestCase(methodName='runTest')

Bases: nova.test.BaseTestCase

setUp()
tearDown()
test_001_allow_all()
test_002_allow_none()
test_003_allow_project_manager()
test_004_allow_sys_and_net()
test_005_allow_sys_no_pm()
class nova.tests.access_unittest.Context
Bases: object