153 vault secrets
This commit is contained in:
+15
-59
@@ -13,8 +13,9 @@
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
</cftry>
|
||||
|
||||
<cfset var local={}/>
|
||||
|
||||
<cfquery name="local.qInstance" result="local.result">
|
||||
select
|
||||
@@ -188,56 +189,8 @@
|
||||
А есть смысл делать это в одну строну? наверно, есть - чтобы не забираться в операцию
|
||||
--->
|
||||
|
||||
<!--- видимо, достаточно нам параметров операции create... но можно и все параметры перебрать --->
|
||||
<!--- <cfquery name="local.qCfsParamRef" result="local.result">
|
||||
select
|
||||
p.svc_operation_cfs_param
|
||||
,p.label
|
||||
,p.descr
|
||||
,p.is_sensitive
|
||||
,r.svc_id as ref_svc_id
|
||||
,r.svc as ref_svc
|
||||
,r.code as ref_code
|
||||
from svc_operation_cfs_param p
|
||||
join svc_operation o on (p.svc_operation_id=o.svc_operation_id)
|
||||
join svc on (o.svc_id=svc.svc_id)
|
||||
join svc r on (p.ref_svc_id=r.svc_id)
|
||||
where svc.svc_id=<cfqueryparam cfsqltype="cf_sql_integer" value="#qInstance.service_id#" null=#!isValid('integer',qInstance.service_id)#/>
|
||||
AND o.operation='create'
|
||||
</cfquery>
|
||||
|
||||
<cfset var dependencies=[]/>
|
||||
<!--- <cfset var dependencies=#local.qCfsParamRef#/> --->
|
||||
<cftry>
|
||||
<cfset var local.instanceData=deserializeJson(local.qCurrentState.instance_data)/>
|
||||
<cfloop query="local.qCfsParamRef">
|
||||
<cfset var paramName = local.qCfsParamRef.svc_operation_cfs_param/>
|
||||
<cfif structKeyExists(local.instanceData, "params") AND structKeyExists(local.instanceData.params, paramName)>
|
||||
<cfset var refKey = structFind(local.instanceData.params, paramName)/>
|
||||
<cfif isValid("guid",refKey)>
|
||||
<!--- *** нужно укрепить изоляцию и проконтролировать принадлежность инстанса данному тенанту --->
|
||||
<cfquery name="qDependency">
|
||||
select e.display_name, e.is_auxiliary
|
||||
from instance e
|
||||
where e.instance_uid = <cfqueryparam cfsqltype="cf_sql_other" value="#refKey#" null=#!isValid('guid',refKey)#/>
|
||||
</cfquery>
|
||||
<cfset var rec = {
|
||||
"param":"#svc_operation_cfs_param#",
|
||||
"descr":"#descr#",
|
||||
"svcId":#ref_svc_id#,
|
||||
"svc":"#ref_svc#",
|
||||
"code":"#ref_code#",
|
||||
"label":"#label#",
|
||||
"uid":"#refKey#",
|
||||
"displayName":"#qDependency.display_name#",
|
||||
"isAuxiliary": #request.castToBool(qDependency.is_auxiliary)#
|
||||
}/>
|
||||
<cfset arrayAppend(dependencies, rec)/>
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfcatch type="ANY"></cfcatch>
|
||||
</cftry> --->
|
||||
|
||||
|
||||
|
||||
<!--- *** здесь уместна параноидальная проверка прав --->
|
||||
<cfquery name="local.qDependency">
|
||||
@@ -329,7 +282,7 @@
|
||||
</cfquery>
|
||||
|
||||
<cftry>
|
||||
<cfset var local.instanceData=deserializeJson(local.qCurrentState.instance_data)/>
|
||||
<cfset local.instanceData=deserializeJson(local.qCurrentState.instance_data)/>
|
||||
<cfloop query="local.qCfsParam">
|
||||
<cfset var paramName = local.qCfsParam.svc_operation_cfs_param/>
|
||||
<cfif structKeyExists(local.instanceData, "params") AND structKeyExists(local.instanceData.params, paramName)>
|
||||
@@ -348,7 +301,10 @@
|
||||
|
||||
|
||||
<cfset var out=structNew("linked")/>
|
||||
<cfset var local.vaultData=structNew("linked")/>
|
||||
<cfset "local.vaultData"=structNew("linked")/>
|
||||
<cfif structKeyExists(instanceData,"vault") AND structKeyExists(instanceData.vault,"fields")>
|
||||
<cfset "local.vaultFields" = #instanceData.vault.fields#/>
|
||||
</cfif>
|
||||
|
||||
<cftry><!--- *** надо бы такие вещи делать асинхронно --->
|
||||
<cfset vaultUrl=""/>
|
||||
@@ -359,10 +315,8 @@
|
||||
<cfset vaultUrl=instanceData.vault.Url/><!--- v002 --->
|
||||
</cfif>
|
||||
|
||||
<!--- url="https://vault.adl.nubes.ru:8200/v1/auth/approle/login" --->
|
||||
|
||||
<cfhttp method="post"
|
||||
url="https://vault.lk.adl.nubes.ru/v1/auth/approle/login"
|
||||
url="#request.vault_login_url#"
|
||||
timeout="3"
|
||||
charset="utf-8"
|
||||
result="res"
|
||||
@@ -387,9 +341,11 @@
|
||||
</cfhttp>
|
||||
|
||||
<!--- *** костыль для перехода от формата v001 к v002 --->
|
||||
|
||||
<cfif structKeyExists(instanceData,"vault") AND structKeyExists(instanceData.vault,"fields")>
|
||||
<cfset local.tempVaultData = #deserializeJson(cred.filecontent).data.data#/>
|
||||
<cfset "local.tempVaultData" = #deserializeJson(cred.filecontent).data.data#/>
|
||||
<cfset "local.vaultData" = #structNew("linked")#/>
|
||||
|
||||
<!--- <cfset "out.vaultData" = #local.tempVaultData#/> --->
|
||||
<cfloop collection=#instanceData.vault.fields# index="i">
|
||||
<cfset var fld=instanceData.vault.fields[i]/>
|
||||
@@ -445,7 +401,7 @@
|
||||
<cfset "out.instance.vaultData"=local.vaultData/>
|
||||
|
||||
<cfset "out.instance.state" = (local.qCurrentState.recordCount GT 0) ? this.helper.appendRecord(structNew("linked"), "", local.currentStateTitleMap, local.qCurrentState, this.helper.snake2camel) : {}/>
|
||||
<!--- <cfset "out.instance.operation"=this.helper.appendRecord(structNew("linked"), "", local.operationTitleMap, local.qOperation, this.helper.snake2camel)/> --->
|
||||
|
||||
<cfset "out.instance.operations"=[]/>
|
||||
<cfloop query=#local.qOperation#>
|
||||
<cfset arrayAppend(out.instance.operations, this.helper.appendRecord(structNew("linked"), "", local.operationTitleMap, local.qOperation, this.helper.snake2camel))/>
|
||||
|
||||
@@ -126,11 +126,13 @@
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cftry><!--- *** времянка, пока глотается ошибка 500 --->
|
||||
|
||||
<!--- Такая бодяга. Кастомные сериализаторы не умеют вложенных структур (поразительно, или я не нашел как). Стандартный сериализатор не умеет выводить дату в ISO 8601. Приходится колхозить и форматировать на стороне БД (насилу подобрал формат). Также на стороне БД приходится конвертировать GUID, потому что драйвер pg jdbc его представляет как структуру из 2 чисел.
|
||||
И то сказать, jsonb как-то странно сериализуется, в 3 поля, вместо одного Value
|
||||
--->
|
||||
<cftry><!--- *** времянка, пока глотается ошибка 500 --->
|
||||
<!--- Такая бодяга. Кастомные сериализаторы не умеют вложенных структур (поразительно, или я не нашел как).
|
||||
Стандартный сериализатор не умеет выводить дату в ISO 8601.
|
||||
Приходится колхозить и форматировать на стороне БД (насилу подобрал формат).
|
||||
Также на стороне БД приходится конвертировать GUID, потому что драйвер pg jdbc его представляет как структуру из 2 чисел.
|
||||
Еще jsonb как-то странно сериализуется, в 3 поля, вместо одного Value (решается преобразованием ::text)
|
||||
--->
|
||||
|
||||
<m:field_set titleMapOut="local.titleMap"
|
||||
lengthOut="local.fieldCount"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<cfcomponent extends="taffy.core.resource" taffy:uri="/instances/{instanceUid}/vault/{secretName}" hint="getting secrets from the vault">
|
||||
|
||||
<cfsilent>
|
||||
<cfimport prefix="m" taglib="../lib"/>
|
||||
<cfset this.helper=CreateObject("component","lib.rest_api_helper")/>
|
||||
</cfsilent>
|
||||
|
||||
<cffunction name="get" hint="Получить секрет">
|
||||
<cfargument name="instanceUid" type="string" required=true hint="type:UUID"/>
|
||||
<cfargument name="secretName" type="string" required=true hint="type:string"/>
|
||||
<!--- <cfargument name="usrId" type="string" hint="type:integer; no need to provide this argument in request, it is injected by IAM"/> --->
|
||||
<!--- arguments.usrId неявно вбрасывается из Application.cfm --->
|
||||
|
||||
<cftry>
|
||||
<cfset this.helper.validateField(arguments, "instanceUid", "guid")/>
|
||||
<cfcatch type="invalidParamValue">
|
||||
<cfreturn representationOf(this.helper.formatBadRequestError(cfcatch)).withStatus(400)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfset var local={}/>
|
||||
<cfset local.vaultData={}/>
|
||||
|
||||
<!--- тут необходимо проконтролировать, что мы смотрим не чужие данные --->
|
||||
<!--- в других местах мы молча возврашаем пустой резалтсет на запрос чужих данных --->
|
||||
<!--- варианты: 403, 404, пустой набор данных --->
|
||||
<cfquery name="local.qCurrentState" result="local.result">
|
||||
select
|
||||
<m:field_set titleMapOut="local.currentStateTitleMap" lengthOut="local.fieldCount">
|
||||
<m:field title="instance_state_uid">st.instance_state_uid::text as instance_state_uid</m:field>
|
||||
<m:field title="v.">st.version</m:field>
|
||||
<m:field title="creator_id">st.creator_id</m:field>
|
||||
<m:field title="dt_state">to_char(st.dt_state, 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZHTZM') as dt_state</m:field>
|
||||
<m:field formatter=#request.castToBool#>st.is_test</m:field>
|
||||
<m:field title="instance_operation_uid">st.instance_operation_uid::text as instance_operation_uid</m:field>
|
||||
<m:field title="instance_data" formatter=#function(x){return (deserializeJson(x))}#>st.instance_data::text as instance_data</m:field>
|
||||
<m:field formatter=#function(x){return (x GT 0)}#>(st.instance_data->>'isDeleted')::boolean as is_deleted</m:field>
|
||||
</m:field_set>
|
||||
from instance_state st
|
||||
join instance e on (st.instance_uid=e.instance_uid)
|
||||
join specification_item i on (e.specification_item_id=i.specification_item_id)
|
||||
where st.instance_uid=<cfqueryparam cfsqltype="cf_sql_other" value="#arguments.instanceUid#"/>
|
||||
AND i.specification_id=<cfqueryparam cfsqltype="cf_sql_integer" value=#arguments.specificationId#/><!--- access protection --->
|
||||
order by st.version desc
|
||||
limit 1
|
||||
</cfquery>
|
||||
|
||||
<cftry>
|
||||
<cfset vaultUrl=""/>
|
||||
<cfset instanceData="#deserializeJson(local.qCurrentState.instance_data)#"/>
|
||||
<cfif structKeyExists(instanceData,"vaultUrl")>
|
||||
<cfset vaultUrl=instanceData.vaultUrl/> <!--- v001 --->
|
||||
<cfelseif structKeyExists(instanceData,"vault")>
|
||||
<cfset vaultUrl=instanceData.vault.Url/><!--- v002 --->
|
||||
</cfif>
|
||||
|
||||
<!--- *** вынести URL в конфиг --->
|
||||
<cfhttp method="post"
|
||||
url="#request.vault_login_url#"
|
||||
timeout="3"
|
||||
charset="utf-8"
|
||||
result="res"
|
||||
>
|
||||
<cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/>
|
||||
<cfhttpparam type="BODY" value='{"role_id":"#request.vault_role_id#","secret_id":"#request.vault_secret_id#"}'/>
|
||||
</cfhttp>
|
||||
<cfset resData=#deserializeJson(res.filecontent)#/>
|
||||
<cfset client_token=#resData.auth.client_token#/>
|
||||
|
||||
<cftry>
|
||||
<cfhttp method="get"
|
||||
url="#vaultUrl#"
|
||||
timeout="3"
|
||||
charset="utf-8"
|
||||
result="cred">
|
||||
<cfhttpparam type="HEADER" name="X-Vault-Token" value="#client_token#">
|
||||
<cfhttpparam type="HEADER" name="User-Agent" value="#request.USER_AGENT#"/>
|
||||
</cfhttp>
|
||||
|
||||
<!--- *** костыль для перехода от формата v001 к v002 --->
|
||||
<cfif structKeyExists(instanceData,"vault")>
|
||||
<cfset "local.tempVaultData" = #deserializeJson(cred.filecontent).data.data#/>
|
||||
<cfset "local.vaultData" = local.tempVaultData[arguments.secretName]/>
|
||||
<!--- <cfelse>
|
||||
<cfset "local.vaultData" = #deserializeJson(cred.filecontent).data.data#/> --->
|
||||
</cfif>
|
||||
|
||||
<cfcatch type="ANY">
|
||||
<cfreturn representationOf(cfcatch).withStatus(500)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
<cfcatch type="ANY">
|
||||
<cfreturn representationOf(cfcatch).withStatus(500)/>
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
|
||||
<cfset var out = structNew("linked")/>
|
||||
<cfset "out.name" = #arguments.secretName#/>
|
||||
<cfset "out.value" = #local.vaultData#/>
|
||||
<cfset "out.queryDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfset "out.runDurationMs"=getTickCount() - request.startTickCount/>
|
||||
<cfreturn representationOf(out) />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
Reference in New Issue
Block a user