497 lines
16 KiB
C++
Executable File
497 lines
16 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2019 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Wind River CGTS Platform Controller Maintenance
|
|
* Access to Openstack Barbican via REST API Interface.
|
|
*
|
|
* This file implements the a set of secret utilities that maintenance
|
|
* calls upon to get/read Barbican secrets from the Barbican Secret storage.
|
|
*
|
|
* The APIs exposed from this file are
|
|
*
|
|
* secretUtil_get_secret - gets the Barbican secret, filtered by name
|
|
* secretUtil_read_secret - reads the payload for a specified secret uuid
|
|
*
|
|
* Each utility is paired with a private handler.
|
|
*
|
|
* secretUtil_handler - handles response for Barbican requests
|
|
*
|
|
* Warning: These calls cannot be nested.
|
|
*
|
|
**/
|
|
|
|
#ifdef __AREA__
|
|
#undef __AREA__
|
|
#endif
|
|
#define __AREA__ "pwd"
|
|
|
|
#include <map>
|
|
#include "nodeBase.h" /* for ... Base Service Header */
|
|
#include "nodeUtil.h" /* for ... Utility Service Header */
|
|
#include "hostUtil.h" /* for ... Host Service Header */
|
|
#include "jsonUtil.h" /* for ... Json utilities */
|
|
#include "secretUtil.h" /* this .. module header */
|
|
|
|
/**************************************************************************
|
|
*
|
|
* Name : secretUtil_manage_secret
|
|
*
|
|
* Description: This FSM serves to fetch a secret from barbican with error
|
|
* handling.
|
|
*
|
|
* The FSM uses a key value pair map list of type barbicanSecret_type
|
|
* defined in httpUtil.h
|
|
*
|
|
* typedef struct
|
|
* {
|
|
* mtc_secretStages_enum stage ;
|
|
* string reference;
|
|
* string payload ;
|
|
* } barbicanSecret_type;
|
|
*
|
|
* The fsm declares a c++ map of this type which serves as
|
|
* a key:value pair list keyed by host uuid string using the
|
|
* secretUtil_find_secret utility. */
|
|
|
|
std::map<string, barbicanSecret_type> secretList;
|
|
|
|
barbicanSecret_type * secretUtil_find_secret ( string & host_uuid )
|
|
{
|
|
std::map<string, barbicanSecret_type>::iterator it;
|
|
it = secretList.find( host_uuid );
|
|
if ( it != secretList.end() )
|
|
{
|
|
return &it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* The FSM uses mtc_secretStages_enum also defined in httpUtil.h
|
|
*
|
|
* MTC_SECRET__START ....... issue request to barbican for the list of
|
|
* secrets for this host_uuid.
|
|
*
|
|
* MTC_SECRET__GET_REF ..... wait for barbican's response with the
|
|
* reference uuid
|
|
*
|
|
* The secret_handler will store the secret reference uuid and change
|
|
* state to MTC_SECRET__GET_PWD or MTC_SECRET__GET_REF_FAIL if the
|
|
* request fails or there are no secrets available.
|
|
*
|
|
* MTC_SECRET__GET_PWD ..... issue a secret read request using the
|
|
* secret reference uuid
|
|
*
|
|
* MTC_SECRET__GET_PWD_REC . wait for barbican's response with the
|
|
* secret string and extract it once recv'ed
|
|
*
|
|
* The secret_handler will store the secret payload and change state
|
|
* to MTC_SECRET__GET_PWD_RECV or MTC_SECRET__GET_PWD_FAIL if the
|
|
* request to provide a secret payload failed or was empty.
|
|
*
|
|
* The secretUtil_get_secret and secretUtil_read_secret http requests
|
|
* are non-blocking.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* event .......... reference to an http libevent event
|
|
* hostname ........ the host's name
|
|
* host_uuid ....... the host's uuid
|
|
* secret_timer .... a maintenance timer for request timeout detection
|
|
* secret_handler .. pointer
|
|
*
|
|
* Updates : secretList host_uuid key value is updated with reference
|
|
* and payload ; the secret.
|
|
*
|
|
* Returns : execution status
|
|
*
|
|
***************************************************************************/
|
|
|
|
barbicanSecret_type * secretUtil_manage_secret ( libEvent & event,
|
|
string & hostname,
|
|
string & host_uuid,
|
|
struct mtc_timer & secret_timer,
|
|
void (*handler)(int, siginfo_t*, void*))
|
|
{
|
|
int rc = PASS;
|
|
std::map<string, barbicanSecret_type>::iterator it;
|
|
it = secretList.find( host_uuid );
|
|
if ( it == secretList.end() )
|
|
{
|
|
barbicanSecret_type secret;
|
|
secret.stage = MTC_SECRET__START;
|
|
secret.payload.clear();
|
|
secret.reference.clear();
|
|
it = secretList.insert( std::pair<string, barbicanSecret_type>( host_uuid, secret ) ).first;
|
|
}
|
|
|
|
if ( event.active == true )
|
|
{
|
|
if (( it->second.stage != MTC_SECRET__GET_REF ) &&
|
|
( it->second.stage != MTC_SECRET__GET_PWD ))
|
|
{
|
|
slog ("%s event is active while in the wrong stage (%d)", hostname.c_str(), it->second.stage );
|
|
event.active = false ; /* correct the error */
|
|
return & it->second ;
|
|
}
|
|
}
|
|
|
|
switch ( it->second.stage )
|
|
{
|
|
case MTC_SECRET__START:
|
|
{
|
|
if ( mtcTimer_expired ( secret_timer ) )
|
|
{
|
|
ilog ("%s query bmc password", hostname.c_str());
|
|
|
|
it->second.reference.clear();
|
|
it->second.payload.clear();
|
|
|
|
rc = secretUtil_get_secret ( event, hostname, host_uuid );
|
|
if (rc)
|
|
{
|
|
elog ("%s get secret request failed (%d)", hostname.c_str(), rc );
|
|
it->second.stage = MTC_SECRET__GET_REF_FAIL;
|
|
}
|
|
else
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_REF;
|
|
mtcTimer_start ( secret_timer, handler, SECRET_REPLY_DELAY );
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
case MTC_SECRET__GET_REF:
|
|
{
|
|
if ( mtcTimer_expired ( secret_timer ) == false )
|
|
{
|
|
if ( event.active == true )
|
|
{
|
|
/* Look for the response */
|
|
if ( event.base )
|
|
{
|
|
dlog ( "%s calling event_base_loop \n", hostname.c_str() );
|
|
event_base_loop ( event.base, EVLOOP_NONBLOCK );
|
|
}
|
|
else
|
|
{
|
|
/* should not get here. event active while base is null
|
|
* try and recover from this error case. */
|
|
slog ("%s active with null base", hostname.c_str());
|
|
event.active = false ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
elog ( "%s timeout waiting for secret reference \n", hostname.c_str() );
|
|
it->second.stage = MTC_SECRET__GET_REF_FAIL ;
|
|
}
|
|
break ;
|
|
}
|
|
case MTC_SECRET__GET_PWD:
|
|
{
|
|
if ( mtcTimer_expired ( secret_timer ) == false )
|
|
{
|
|
if ( event.active == true )
|
|
{
|
|
/* Look for the response */
|
|
if ( event.base )
|
|
{
|
|
dlog ( "%s calling event_base_loop \n", hostname.c_str() );
|
|
event_base_loop( event.base, EVLOOP_NONBLOCK );
|
|
}
|
|
else
|
|
{
|
|
/* should not get here. event active while base is null
|
|
* try and recover from this error case. */
|
|
slog ("%s active with null base", hostname.c_str() );
|
|
event.active = false ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
elog ( "%s timeout waiting for secret payload \n", hostname.c_str() );
|
|
it->second.stage = MTC_SECRET__GET_PWD_FAIL ;
|
|
}
|
|
break ;
|
|
}
|
|
|
|
case MTC_SECRET__GET_REF_RECV:
|
|
{
|
|
mtcTimer_reset( secret_timer );
|
|
httpUtil_free_conn ( event );
|
|
httpUtil_free_base ( event );
|
|
|
|
rc = secretUtil_read_secret ( event, hostname, host_uuid );
|
|
if (rc)
|
|
{
|
|
wlog ( "%s call to secretUtil_read_secret failed \n", hostname.c_str() );
|
|
it->second.stage = MTC_SECRET__GET_PWD_FAIL;
|
|
}
|
|
else
|
|
{
|
|
dlog ("%s waiting on secret password ; timeout in %d secs\n", hostname.c_str(), SECRET_REPLY_DELAY);
|
|
it->second.stage = MTC_SECRET__GET_PWD ;
|
|
mtcTimer_start ( secret_timer, handler, SECRET_REPLY_DELAY );
|
|
}
|
|
break ;
|
|
}
|
|
|
|
case MTC_SECRET__GET_REF_FAIL:
|
|
case MTC_SECRET__GET_PWD_FAIL:
|
|
{
|
|
if ( it->second.stage == MTC_SECRET__GET_REF_FAIL )
|
|
{
|
|
wlog ( "%s failed to get secret reference \n", hostname.c_str() );
|
|
}
|
|
else
|
|
{
|
|
wlog ( "%s failed to get secret payload \n", hostname.c_str() );
|
|
}
|
|
it->second.stage = MTC_SECRET__START ;
|
|
mtcTimer_reset ( secret_timer );
|
|
mtcTimer_start ( secret_timer, handler, SECRET_RETRY_DELAY );
|
|
httpUtil_free_conn ( event );
|
|
httpUtil_free_base ( event );
|
|
break ;
|
|
}
|
|
|
|
default:
|
|
{
|
|
it->second.stage = MTC_SECRET__START ;
|
|
}
|
|
} // switch
|
|
|
|
return & it->second ;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Name : secretUtil_get_secret
|
|
*
|
|
* Purpose : Issue an Barbican GET request for a specified secret name
|
|
* to manage secret's reference.
|
|
*
|
|
*/
|
|
|
|
int secretUtil_get_secret ( libEvent & event,
|
|
string & hostname,
|
|
string & host_uuid )
|
|
{
|
|
dlog ("%s get secret", hostname.c_str());
|
|
httpUtil_event_init ( &event,
|
|
host_uuid,
|
|
"secretUtil_get_secret",
|
|
hostUtil_getServiceIp (SERVICE_SECRET),
|
|
hostUtil_getServicePort(SERVICE_SECRET));
|
|
|
|
std::map<string, barbicanSecret_type>::iterator it;
|
|
it = secretList.find( host_uuid );
|
|
if ( it != secretList.end() )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_REF;
|
|
}
|
|
else
|
|
{
|
|
elog ("%s failed to find secret record (%s)\n",
|
|
hostname.c_str(),
|
|
host_uuid.c_str());
|
|
return FAIL;
|
|
}
|
|
|
|
event.hostname = hostname ;
|
|
event.uuid = host_uuid;
|
|
|
|
event.token.url = MTC_SECRET_LABEL;
|
|
event.token.url.append(MTC_SECRET_NAME);
|
|
event.token.url.append(host_uuid);
|
|
event.token.url.append(MTC_SECRET_BATCH);
|
|
event.token.url.append(MTC_SECRET_BATCH_MAX);
|
|
event.address = event.token.url;
|
|
|
|
event.blocking = false;
|
|
event.request = BARBICAN_GET_SECRET;
|
|
event.operation = "get secret reference";
|
|
event.type = EVHTTP_REQ_GET ;
|
|
event.timeout = HTTP_SECRET_TIMEOUT ;
|
|
event.handler = &secretUtil_handler ;
|
|
|
|
hlog ("%s secretUtil_get_secret %s\n",
|
|
hostname.c_str(), event.token.url.c_str() );
|
|
|
|
return ( httpUtil_api_request ( event ) ) ;
|
|
}
|
|
|
|
/* ******************************************************************
|
|
*
|
|
* Name: secretUtil_read_secret
|
|
*
|
|
* Purpose: Issue an Barbican GET request for a specified secret uuid
|
|
* to read secret's payload, ie password itself.
|
|
*
|
|
*********************************************************************/
|
|
|
|
int secretUtil_read_secret ( libEvent & event,
|
|
string & hostname,
|
|
string & host_uuid )
|
|
{
|
|
dlog ("%s read secret", hostname.c_str());
|
|
httpUtil_event_init ( &event,
|
|
host_uuid,
|
|
"secretUtil_read_secret",
|
|
hostUtil_getServiceIp (SERVICE_SECRET),
|
|
hostUtil_getServicePort(SERVICE_SECRET));
|
|
|
|
string bm_pw_reference;
|
|
std::map<string, barbicanSecret_type>::iterator it;
|
|
it = secretList.find( host_uuid );
|
|
if ( it != secretList.end() )
|
|
{
|
|
bm_pw_reference = it->second.reference;
|
|
it->second.stage = MTC_SECRET__GET_PWD;
|
|
}
|
|
else
|
|
{
|
|
elog ("%s failed to find secret record\n", host_uuid.c_str());
|
|
return FAIL;
|
|
}
|
|
|
|
event.hostname = hostname ;
|
|
event.uuid = host_uuid;
|
|
|
|
event.token.url = MTC_SECRET_LABEL;
|
|
event.token.url.append("/");
|
|
event.token.url.append(bm_pw_reference);
|
|
event.token.url.append("/");
|
|
event.token.url.append(MTC_SECRET_PAYLOAD);
|
|
event.address = event.token.url;
|
|
|
|
event.blocking = false;
|
|
event.request = BARBICAN_READ_SECRET ;
|
|
event.operation = "get secret payload";
|
|
event.type = EVHTTP_REQ_GET ;
|
|
event.timeout = HTTP_SECRET_TIMEOUT ;
|
|
event.handler = &secretUtil_handler ;
|
|
|
|
hlog ("%s secretUtil_read_secret %s",
|
|
hostname.c_str(), event.token.url.c_str() );
|
|
|
|
return ( httpUtil_api_request ( event ) ) ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Name : secretUtil_handler
|
|
*
|
|
* Description: The handles the barbican get request
|
|
* responses for the following messages
|
|
*
|
|
* BARBICAN_GET_SECRET,
|
|
* BARBICAN_READ_SECRET
|
|
*
|
|
*******************************************************************/
|
|
|
|
int secretUtil_handler ( libEvent & event )
|
|
{
|
|
/* Declare and clean the json info object string containers */
|
|
jsonUtil_secret_type json_info ;
|
|
|
|
string hn = event.hostname ;
|
|
|
|
/* handler called */
|
|
event.active = false ;
|
|
|
|
std::map<string, barbicanSecret_type>::iterator it;
|
|
it = secretList.find( event.uuid );
|
|
if ( it == secretList.end() )
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
if ( event.request == BARBICAN_GET_SECRET )
|
|
{
|
|
if ( event.status )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_REF_FAIL;
|
|
elog ("%s failed to get secret ; %d\n", hn.c_str(), event.status) ;
|
|
return 0 ;
|
|
}
|
|
int rc = jsonUtil_secret_load ( event.uuid,
|
|
(char*)event.response.data(),
|
|
json_info );
|
|
if ( rc != PASS )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_REF_FAIL;
|
|
elog ("%s failed to parse secret response : %s (%d:%d)\n",
|
|
hn.c_str(),
|
|
event.response.c_str(),
|
|
rc, event.status );
|
|
}
|
|
else
|
|
{
|
|
size_t pos = json_info.secret_ref.find_last_of( '/' );
|
|
it->second.reference = json_info.secret_ref.substr( pos+1 );
|
|
|
|
if ( it->second.reference.empty() )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_REF_FAIL;
|
|
elog ("%s no barbican secret reference found : %s (%d)\n",
|
|
hn.c_str(),
|
|
event.response.c_str(),
|
|
FAIL_OPERATION ) ;
|
|
}
|
|
else
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_REF_RECV;
|
|
dlog ("%s barbican secret reference found\n", hn.c_str() ) ;
|
|
}
|
|
}
|
|
}
|
|
else if ( event.request == BARBICAN_READ_SECRET )
|
|
{
|
|
if ( event.status == HTTP_NOTFOUND )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_PWD_FAIL;
|
|
elog ("%s no barbican secret payload found : %s (rc:%d:%d)\n",
|
|
hn.c_str(),
|
|
event.response.c_str(),
|
|
event.status, FAIL_NOT_FOUND );
|
|
}
|
|
else if ( event.status != PASS )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_PWD_FAIL;
|
|
elog ("%s failed to read secret : %s (rc:%d)\n",
|
|
hn.c_str(),
|
|
event.response.c_str(),
|
|
event.status );
|
|
}
|
|
else if ( event.response.empty() )
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_PWD_FAIL;
|
|
wlog ("%s secret payload is empty (rc:%d)\n",
|
|
hn.c_str(),
|
|
FAIL_OPERATION ) ;
|
|
}
|
|
else
|
|
{
|
|
it->second.stage = MTC_SECRET__GET_PWD_RECV;
|
|
it->second.payload = event.response;
|
|
dlog ("%s secret payload : %s\n", hn.c_str(), event.response.c_str() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
slog ("%s unsupported secret request (rc:%d)\n", hn.c_str(), FAIL_BAD_CASE );
|
|
}
|
|
|
|
return ( 0 ) ;
|
|
}
|