Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sqlite CA backing store type #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## In progress
- Add sqlite option for the CA backing store type

## 0.2.0 (2014-02-25)
- Add environment-specific public keys
- Run ssh-add as part of get cert so openssh will detect the new cert
Expand Down
12 changes: 10 additions & 2 deletions scripts/sign_key
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ from contextlib import closing

import ssh_ca
import ssh_ca.s3
import ssh_ca.sqlite


ca_map = {
's3': ssh_ca.s3.S3Authority,
'sqlite': ssh_ca.sqlite.SqliteAuthority,
}


if __name__ == '__main__':
Expand All @@ -37,7 +44,8 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser(__doc__)
parser.add_argument('-a', '--authority',
dest='authority', default=default_authority,
help='Pick one: s3',
choices=['s3', 'sqlite'],
help='Specify CA backing store type',
)
parser.add_argument('-c', '--config-file',
default=default_config,
Expand Down Expand Up @@ -99,7 +107,7 @@ if __name__ == '__main__':

try:
# Create our CA
ca = ssh_ca.s3.S3Authority(config, ssh_ca_section, ca_key)
ca = ca_map[args.authority](config, ssh_ca_section, ca_key)
except ssh_ca.SSHCAInvalidConfiguration, e:
print 'Issue with creating CA: %s' % e.message
sys.exit(1)
Expand Down
87 changes: 87 additions & 0 deletions ssh_ca/sqlite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import datetime
import json
import sqlite3

import ssh_ca


class SqliteAuthority(ssh_ca.Authority):
def __init__(self, config, ssh_ca_section, ca_key):
super(SqliteAuthority, self).__init__(ca_key)

self.dbfile = ssh_ca.get_config_value(
config, ssh_ca_section, 'dbfile', required=True)
self.conn = sqlite3.connect(self.dbfile)
self._check_schema()

def _check_schema(self):
version = self.conn.execute('PRAGMA user_version').fetchone()
if version[0] == 0:
with self.conn:
self.conn.execute('PRAGMA user_version=1')
self.conn.execute(
'create table keys (name, environment, public_key)')
self.conn.execute(
'create table serial (row, serial integer)')
self.conn.execute(
'create table audit_log (entry integer primary key, log)')
self.conn.execute(
'insert into serial (row, serial) values (1, 0)')

def increment_serial_number(self):
with self.conn:
self.conn.execute('update serial set serial=serial+1 where row=1')
cur = self.conn.execute('select serial from serial where row=1')
new_serial = cur.fetchone()[0]
return new_serial

def get_public_key(self, username, environment):
select = 'select public_key from keys where name is ?'
args = (username, )
cur = self.conn.execute(select, args)
result = cur.fetchone()
if result:
return result[0]
else:
return None

def upload_public_key(self, username, key_file):
key = open(key_file).read()
arglist = (username, key)
insert_stmt = 'insert into keys (name, public_key) values (?, ?)'
with self.conn:
self.conn.execute(insert_stmt, arglist)

def upload_public_key_cert(self, username, cert_contents):
return "%s: %s" % (username, cert_contents)

def make_host_audit_log(self, serial, valid_for, ca_key_filename,
reason, hostnames):
audit_info = {
'valid_for': valid_for,
'ca_key_filename': ca_key_filename,
'reason': reason,
'hostnames': hostnames,
}
return self.drop_audit_blob(serial, audit_info)

def make_audit_log(self, serial, valid_for, username,
ca_key_filename, reason, principals):
audit_info = {
'username': username,
'valid_for': valid_for,
'ca_key_filename': ca_key_filename,
'reason': reason,
'principals': principals,
}
return self.drop_audit_blob(serial, audit_info)

def drop_audit_blob(self, serial, blob):
timestamp = datetime.datetime.strftime(
datetime.datetime.utcnow(), '%Y-%m-%d-%H:%M:%S.%f')
blob['serial'] = serial
blob['timestamp'] = timestamp

arglist = (None, json.dumps(blob))
with self.conn:
self.conn.execute('insert into audit_log values (?, ?)', arglist)