Commit 8be26639 authored by Leigh Stoller's avatar Leigh Stoller

Add new options to CreateSliver/Provision; supply an x509 certificate and

private key.

The goal is to distribute an experiment wide certificate and private
key. At the moment this is just a self signed x509 certificate and the
accompanying rsa key. In PEM format. The same cert/key will be distributed
across multiple aggregates.

An openssh key pair can be trivially derived from the private key. Or the
public part can be derived from the certificate. A quick google will show
show.

Initially, you will need to run tmcc directly to get them, using the
geni_certificate and geni_key commands.
parent ec07c10c
......@@ -1405,9 +1405,9 @@ sub GetManifest($)
return $response->value()->{'manifest'};
}
sub Provision($$$)
sub Provision($$$$)
{
my ($self, $perrmsg, $keys) = @_;
my ($self, $perrmsg, $keys, $cert, $key) = @_;
my $authority = $self->GetGeniAuthority();
my $urn = $self->aggregate_urn();
my $geniuser = $self->instance()->GetGeniUser();
......@@ -1439,6 +1439,8 @@ sub Provision($$$)
"geni_speaking_for" => $geniuser->urn(),
"geni_users" => [{'urn' => $geniuser->urn(),
'keys' => $keys }],
"geni_certificate" => $cert,
"geni_key" => $key,
});
my $cmurl = $authority->url();
......
......@@ -89,6 +89,7 @@ my $SSHSETUP = "$TB/sbin/aptssh-setup";
my $ADDPUBKEY = "$TB/sbin/addpubkey";
my $UPDATEGENIUSER= "$TB/sbin/protogeni/updategeniuser";
my $STITCHER = "$TB/gcf/src/stitcher.py";
my $OPENSSL = "/usr/bin/openssl";
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
......@@ -589,6 +590,27 @@ if (defined($profile)) {
}
}
#
# Generate a new ssl key/cert to be used to derive an ssh key pair,
# or whatever else is needed. This is sent along as an option when the
# sliver is created (or provisioned, when stitching).
#
my $sslkeyfile = "/tmp/key$$.pem";
my $sslcrtfile = "/tmp/crt$$.pem";
system("$OPENSSL req -x509 -newkey rsa:2048 ".
"-keyout $sslkeyfile -out $sslcrtfile ".
"-days 2000 -nodes -subj '/CN=localhost' -text");
if ($?) {
unlink($sslkeyfile);
unlink($sslcrtfile);
fatal("Could not generate ssl key/cert");
}
my $sslkey = `cat $sslkeyfile`;
my $sslcrt = `cat $sslcrtfile`;
unlink($sslkeyfile);
unlink($sslcrtfile);
#
#
# Now generate a slice registration and credential
......@@ -661,6 +683,8 @@ my $blob = {'uuid' => $quickvm_uuid,
'status' => "created",
'servername' => $SERVER_NAME,
'rspec' => $rspecstr,
'cert' => $sslcrt,
'privkey' => $sslkey,
};
if (defined($project)) {
$blob->{"pid"} = $project->pid();
......@@ -1031,7 +1055,10 @@ sub CreateSliver($)
[$slice_credential->asString(),
$speaksfor_credential->asString(),
@dataset_credentials
]});
],
"certificate" => $sslcrt,
"key" => $sslkey,
});
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS) {
if (defined($response) &&
......@@ -1319,7 +1346,7 @@ sub RunStitcher()
return 0;
}
print "Provisioning at $urn\n";
if ($aggobj->Provision(\$errmsg, \@sshkeys)) {
if ($aggobj->Provision(\$errmsg, \@sshkeys, $sslcrt, $sslkey)) {
$aggobj->SetStatus("failed");
$webtask->output($errmsg);
$webtask->Exited(-1);
......
......@@ -222,6 +222,14 @@ CREATE TABLE `geni_userkeys` (
INDEX `uuid` (`uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `geni_slicecerts`;
CREATE TABLE `geni_slicecerts` (
`uuid` varchar(40) NOT NULL default '',
`cert` text,
`privkey` text,
INDEX `uuid` (`uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `geni_resources`;
CREATE TABLE `geni_resources` (
`pid` varchar(12) NOT NULL default '',
......
......@@ -385,6 +385,14 @@ sub CreateSliver()
'credentials' => $credentials,
'keys' => $sliver_keys
};
if (defined($options)) {
if (exists($options->{'geni_certificate'})) {
$create_args->{'certificate'} = $options->{'geni_certificate'};
}
if (exists($options->{'geni_key'})) {
$create_args->{'key'} = $options->{'geni_key'};
}
}
my $response = GeniCMV2::CreateSliver($create_args);
if (!ref($response)) {
# This is cause GeniCMV2::CreateSliver does a fork, and the child
......@@ -1027,7 +1035,14 @@ sub Provision
'credentials' => $credentials,
'keys' => $sliver_keys
};
if (defined($options)) {
if (exists($options->{'geni_certificate'})) {
$args->{'certificate'} = $options->{'geni_certificate'};
}
if (exists($options->{'geni_key'})) {
$args->{'key'} = $options->{'geni_key'};
}
}
my $response = GeniCMV2::RedeemTicket($args);
if (! GeniResponse::IsError($response)) {
my $description = Describe($urn_args, $credential_args, []);
......
......@@ -482,6 +482,18 @@ sub CreateSliver($)
}
main::AddLogfileMetaDataFromSlice($slice);
#
# If we got a cert/key, record them for the slice. This is a
# generic openssl key/cert that is stored on the nodes (and from
# which an ssh key pair can be derived).
#
if (exists($argref->{'certificate'}) || exists($argref->{'key'})) {
$slice->AddGenericCert((exists($argref->{'certificate'}) ?
$argref->{'certificate'} : undef),
(exists($argref->{'key'}) ?
$argref->{'key'} : undef));
}
# Make sure that the next phase sees all changes.
Experiment->FlushAll();
Node->FlushAll();
......
......@@ -44,7 +44,7 @@ use GeniUser;
use GeniHRN;
use English;
use libEmulab;
use emutil qw(TBGetUniqueIndex);
use emutil;
use Date::Parse;
use Data::Dumper;
use vars qw();
......@@ -354,6 +354,8 @@ sub Delete($)
my $uuid = $self->uuid();
my $idx = $self->idx();
DBQueryWarn("delete from geni_slicecerts where uuid='$uuid'")
or return -1;
DBQueryWarn("delete from geni_bindings where slice_uuid='$uuid'")
or return -1;
DBQueryWarn("delete from geni_certificates where uuid='$uuid'")
......@@ -1452,6 +1454,30 @@ sub SetPublicID($)
return 0;
}
#
# Add a generic certificate/key for a slice.
#
sub AddGenericCert($$$)
{
my ($self, $cert, $key) = @_;
my $uuid = $self->uuid();
my $query = "insert into geni_slicecerts set uuid='$uuid' ";
if (defined($cert)) {
return -1
if (!TBcheck_dbslot($cert, "default", "fulltext",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR));
$query .= ",cert=" . DBQuoteSpecial($cert);
}
if (defined($key)) {
return -1
if (!TBcheck_dbslot($key, "default", "fulltext",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR));
$query .= ",privkey=" . DBQuoteSpecial($key);
}
return DBQueryWarn($query);
}
##########################################################################
#
package GeniSlice::ClientSliver;
......
#
# APT Changes.
#
use strict;
use GeniDB;
sub DoUpdate($$$)
my ($dbhandle, $dbname, $version) = @_;
DBSetDefault($dbhandle);
if (!DBTableExists("geni_slicecerts")) {
DBQueryFatal("CREATE TABLE `geni_slicecerts` ( ".
" `uuid` varchar(40) NOT NULL default '', ".
" `cert` text, ".
" `privkey` text, ".
" INDEX `uuid` (`uuid`)".
") ENGINE=MyISAM DEFAULT CHARSET=latin1");
}
return 0;
}
1;
# Local Variables:
# mode:perl
# End:
......@@ -398,6 +398,8 @@ COMMAND_PROTOTYPE(dogeniuserurn);
COMMAND_PROTOTYPE(dogeniuseremail);
COMMAND_PROTOTYPE(dogenigeniuser);
COMMAND_PROTOTYPE(dogenimanifest);
COMMAND_PROTOTYPE(dogenicert);
COMMAND_PROTOTYPE(dogenikey);
COMMAND_PROTOTYPE(dogenicontrolmac);
COMMAND_PROTOTYPE(dogeniversion);
COMMAND_PROTOTYPE(dogenigetversion);
......@@ -532,6 +534,8 @@ struct command {
/* Yes, "geni_user" is a stupid name. Wasn't my idea. */
{ "geni_geni_user", FULLCONFIG_NONE, 0, dogenigeniuser },
{ "geni_manifest", FULLCONFIG_NONE, 0, dogenimanifest },
{ "geni_certificate", FULLCONFIG_NONE, 0, dogenicert },
{ "geni_key", FULLCONFIG_NONE, 0, dogenikey },
{ "geni_control_mac", FULLCONFIG_NONE, 0, dogenicontrolmac },
{ "geni_version", FULLCONFIG_NONE, 0, dogeniversion },
{ "geni_getversion", FULLCONFIG_NONE, 0, dogenigetversion },
......@@ -12411,6 +12415,68 @@ static char *getgenimanifest( tmcdreq_t *reqp ) {
return strdup( buf );
}
static char *getgenicert( tmcdreq_t *reqp ) {
MYSQL_RES *res;
char buf[ MAXTMCDPACKET ];
buf[0] = (char) NULL;
res = mydb_query( "SELECT c.cert FROM `geni-cm`.geni_slivers AS s, "
"`geni-cm`.geni_slicecerts AS c WHERE "
"s.resource_uuid='%s' AND "
"c.uuid = s.slice_uuid", 1, reqp->nodeuuid );
if( !res ) {
error( "getgenicert: %s: DB error getting certificate!\n",
reqp->nodeid );
return NULL;
}
if( mysql_num_rows( res ) ) {
MYSQL_ROW row = mysql_fetch_row( res );
GOUTPUT( buf, sizeof buf, "%s", row[ 0 ] );
}
mysql_free_result( res );
if( verbose )
info( "%s: getgenicert: %s", reqp->nodeid, buf );
return strdup( buf );
}
static char *getgenikey( tmcdreq_t *reqp ) {
MYSQL_RES *res;
char buf[ MAXTMCDPACKET ];
buf[0] = (char) NULL;
res = mydb_query( "SELECT c.privkey FROM `geni-cm`.geni_slivers AS s, "
"`geni-cm`.geni_slicecerts AS c WHERE "
"s.resource_uuid='%s' AND "
"c.uuid = s.slice_uuid", 1, reqp->nodeuuid );
if( !res ) {
error( "getgenikey: %s: DB error getting certificate!\n",
reqp->nodeid );
return NULL;
}
if( mysql_num_rows( res ) ) {
MYSQL_ROW row = mysql_fetch_row( res );
GOUTPUT( buf, sizeof buf, "%s", row[ 0 ] );
}
mysql_free_result( res );
if( verbose )
info( "%s: getgenikey: %s", reqp->nodeid, buf );
return strdup( buf );
}
static char *getgenigeniuser( tmcdreq_t *reqp ) {
MYSQL_RES *res;
......@@ -12691,6 +12757,8 @@ MAKEGENICOMMAND(userurn)
MAKEGENICOMMAND(useremail)
MAKEGENICOMMAND(geniuser)
MAKEGENICOMMAND(manifest)
MAKEGENICOMMAND(cert)
MAKEGENICOMMAND(key)
MAKEGENICOMMAND(controlmac)
MAKEGENICOMMAND(version)
MAKEGENICOMMAND(getversion)
......@@ -12726,7 +12794,9 @@ struct genicommand {
{ "user_email", getgeniuseremail, 1, "Show the e-mail address of this "
"sliver's creator" },
{ "user_urn", getgeniuserurn, 1, "Show the URN of this sliver's creator" },
{ "version", getgeniversion, 1, NULL }
{ "version", getgeniversion, 1, NULL },
{ "certificate", getgenicert, 1, NULL },
{ "key", getgenikey, 1, NULL },
};
COMMAND_PROTOTYPE(dogenicommands)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment