mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-09 15:38:03 -05:00
feat(agent): added agent template support to pull dynamic secret
This commit is contained in:
@@ -34,20 +34,21 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide
|
|||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
lease: DynamicSecretLeasesSchema,
|
lease: DynamicSecretLeasesSchema,
|
||||||
|
dynamicSecret: SanitizedDynamicSecretSchema,
|
||||||
data: z.unknown()
|
data: z.unknown()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { data, lease } = await server.services.dynamicSecretLease.create({
|
const { data, lease, dynamicSecret } = await server.services.dynamicSecretLease.create({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.orgId,
|
||||||
...req.body
|
...req.body
|
||||||
});
|
});
|
||||||
return { lease, data };
|
return { lease, data, dynamicSecret };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const dynamicSecretLeaseDALFactory = (db: TDbClient) => {
|
|||||||
const findById = async (id: string, tx?: Knex) => {
|
const findById = async (id: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const doc = await (tx || db)(TableName.DynamicSecretLease)
|
const doc = await (tx || db)(TableName.DynamicSecretLease)
|
||||||
.where({ id })
|
.where({ [`${TableName.DynamicSecretLease}.id` as "id"]: id })
|
||||||
.first()
|
.first()
|
||||||
.join(
|
.join(
|
||||||
TableName.DynamicSecret,
|
TableName.DynamicSecret,
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ export const dynamicSecretLeaseQueueServiceFactory = ({
|
|||||||
{ dynamicSecretCfgId },
|
{ dynamicSecretCfgId },
|
||||||
{
|
{
|
||||||
jobId: dynamicSecretCfgId,
|
jobId: dynamicSecretCfgId,
|
||||||
|
backoff: {
|
||||||
|
type: "exponential",
|
||||||
|
delay: 3000
|
||||||
|
},
|
||||||
removeOnFail: {
|
removeOnFail: {
|
||||||
count: 3
|
count: 3
|
||||||
},
|
},
|
||||||
@@ -46,6 +50,10 @@ export const dynamicSecretLeaseQueueServiceFactory = ({
|
|||||||
{ leaseId },
|
{ leaseId },
|
||||||
{
|
{
|
||||||
jobId: leaseId,
|
jobId: leaseId,
|
||||||
|
backoff: {
|
||||||
|
type: "exponential",
|
||||||
|
delay: 3000
|
||||||
|
},
|
||||||
delay: expiry,
|
delay: expiry,
|
||||||
removeOnFail: {
|
removeOnFail: {
|
||||||
count: 3
|
count: 3
|
||||||
@@ -64,12 +72,11 @@ export const dynamicSecretLeaseQueueServiceFactory = ({
|
|||||||
if (job.name === QueueJobs.DynamicSecretRevocation) {
|
if (job.name === QueueJobs.DynamicSecretRevocation) {
|
||||||
const { leaseId } = job.data as { leaseId: string };
|
const { leaseId } = job.data as { leaseId: string };
|
||||||
logger.info("Dynamic secret lease revocation started: ", leaseId, job.id);
|
logger.info("Dynamic secret lease revocation started: ", leaseId, job.id);
|
||||||
|
|
||||||
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
const dynamicSecretLease = await dynamicSecretLeaseDAL.findById(leaseId);
|
||||||
if (!dynamicSecretLease) throw new DisableRotationErrors({ message: "Dynamic secret lease not found" });
|
if (!dynamicSecretLease) throw new DisableRotationErrors({ message: "Dynamic secret lease not found" });
|
||||||
|
|
||||||
const dynamicSecretCfg = await dynamicSecretDAL.findById(dynamicSecretLease.dynamicSecretId);
|
const dynamicSecretCfg = dynamicSecretLease.dynamicSecret;
|
||||||
if (!dynamicSecretCfg) throw new DisableRotationErrors({ message: "Dynamic secret not found" });
|
|
||||||
|
|
||||||
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
const selectedProvider = dynamicSecretProviders[dynamicSecretCfg.type as DynamicSecretProviders];
|
||||||
const decryptedStoredInput = JSON.parse(
|
const decryptedStoredInput = JSON.parse(
|
||||||
infisicalSymmetricDecrypt({
|
infisicalSymmetricDecrypt({
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
externalEntityId: entityId
|
externalEntityId: entityId
|
||||||
});
|
});
|
||||||
await dynamicSecretQueueService.setLeaseRevocation(dynamicSecretLease.id, Number(expireAt) - Number(new Date()));
|
await dynamicSecretQueueService.setLeaseRevocation(dynamicSecretLease.id, Number(expireAt) - Number(new Date()));
|
||||||
return { lease: dynamicSecretLease, data };
|
return { lease: dynamicSecretLease, dynamicSecret: dynamicSecretCfg, data };
|
||||||
};
|
};
|
||||||
|
|
||||||
const renewLease = async ({
|
const renewLease = async ({
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000;
|
|||||||
|
|
||||||
const generatePassword = (size?: number) => {
|
const generatePassword = (size?: number) => {
|
||||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*'$#";
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*'$#";
|
||||||
return customAlphabet(charset, 20)(size);
|
return customAlphabet(charset, 32)(size);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SqlDatabaseProvider = (): TDynamicProviderFns => {
|
export const SqlDatabaseProvider = (): TDynamicProviderFns => {
|
||||||
@@ -50,7 +50,7 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
|
|||||||
const providerInputs = await validateProviderInputs(inputs);
|
const providerInputs = await validateProviderInputs(inputs);
|
||||||
const db = await getClient(providerInputs);
|
const db = await getClient(providerInputs);
|
||||||
|
|
||||||
const username = alphaNumericNanoId(16);
|
const username = alphaNumericNanoId(21);
|
||||||
const password = generatePassword();
|
const password = generatePassword();
|
||||||
const expiration = new Date(expireAt).toISOString();
|
const expiration = new Date(expireAt).toISOString();
|
||||||
|
|
||||||
|
|||||||
1
cli/.gitignore
vendored
1
cli/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.infisical.json
|
.infisical.json
|
||||||
dist/
|
dist/
|
||||||
|
agent-config.test.yaml
|
||||||
|
|||||||
@@ -535,3 +535,23 @@ func CallGetRawSecretsV3(httpClient *resty.Client, request GetRawSecretsV3Reques
|
|||||||
|
|
||||||
return getRawSecretsV3Response, nil
|
return getRawSecretsV3Response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CallCreateDynamicSecretLeaseV1(httpClient *resty.Client, request CreateDynamicSecretLeaseV1Request) (CreateDynamicSecretLeaseV1Response, error) {
|
||||||
|
var createDynamicSecretLeaseResponse CreateDynamicSecretLeaseV1Response
|
||||||
|
response, err := httpClient.
|
||||||
|
R().
|
||||||
|
SetResult(&createDynamicSecretLeaseResponse).
|
||||||
|
SetHeader("User-Agent", USER_AGENT).
|
||||||
|
SetBody(request).
|
||||||
|
Post(fmt.Sprintf("%v/v1/dynamic-secrets/leases", config.INFISICAL_URL))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return CreateDynamicSecretLeaseV1Response{}, fmt.Errorf("CreateDynamicSecretLeaseV1: Unable to complete api request [err=%w]", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.IsError() {
|
||||||
|
return CreateDynamicSecretLeaseV1Response{}, fmt.Errorf("CreateDynamicSecretLeaseV1: Unsuccessful response [%v %v] [status-code=%v] [response=%v]", response.Request.Method, response.Request.URL, response.StatusCode(), response.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return createDynamicSecretLeaseResponse, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -501,6 +501,28 @@ type UniversalAuthRefreshResponse struct {
|
|||||||
AccessTokenMaxTTL int `json:"accessTokenMaxTTL"`
|
AccessTokenMaxTTL int `json:"accessTokenMaxTTL"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateDynamicSecretLeaseV1Request struct {
|
||||||
|
Environment string `json:"environment"`
|
||||||
|
ProjectSlug string `json:"projectSlug"`
|
||||||
|
SecretPath string `json:"secretPath,omitempty"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
TTL string `json:"ttl,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateDynamicSecretLeaseV1Response struct {
|
||||||
|
Lease struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
ExpireAt string `json:"expireAt"`
|
||||||
|
} `json:"lease"`
|
||||||
|
DynamicSecret struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
DefaultTTL string `json:"defaultTTL"`
|
||||||
|
MaxTTL string `json:"maxTTL"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
} `json:"dynamicSecret"`
|
||||||
|
Data map[string]interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
type GetRawSecretsV3Request struct {
|
type GetRawSecretsV3Request struct {
|
||||||
Environment string `json:"environment"`
|
Environment string `json:"environment"`
|
||||||
WorkspaceId string `json:"workspaceId"`
|
WorkspaceId string `json:"workspaceId"`
|
||||||
|
|||||||
@@ -84,6 +84,30 @@ type Template struct {
|
|||||||
} `yaml:"config"`
|
} `yaml:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DynamicSecretLease struct {
|
||||||
|
LeaseID string
|
||||||
|
ExpireAt time.Time
|
||||||
|
Environment string
|
||||||
|
SecretPath string
|
||||||
|
Slug string
|
||||||
|
ProjectSlug string
|
||||||
|
Data map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DynamicSecretLeaseManger []DynamicSecretLease
|
||||||
|
|
||||||
|
func (d DynamicSecretLeaseManger) FindLease(projectSlug, environment, secretPath, slug string) *DynamicSecretLease {
|
||||||
|
for _, lease := range d {
|
||||||
|
// presentTime := time.Now()
|
||||||
|
// isExpired := presentTime.Before(lease.ExpireAt.Add(-15 * time.Second))
|
||||||
|
if lease.SecretPath == secretPath && lease.Environment == environment && lease.ProjectSlug == projectSlug && lease.Slug == slug {
|
||||||
|
return &lease
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func ReadFile(filePath string) ([]byte, error) {
|
func ReadFile(filePath string) ([]byte, error) {
|
||||||
return ioutil.ReadFile(filePath)
|
return ioutil.ReadFile(filePath)
|
||||||
}
|
}
|
||||||
@@ -234,11 +258,24 @@ func secretTemplateFunction(accessToken string, existingEtag string, currentEtag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dynamicSecretTemplateFunction(accessToken string) func(string, string, string, string) (map[string]interface{}, error) {
|
||||||
|
return func(projectSlug, envSlug, secretPath, slug string) (map[string]interface{}, error) {
|
||||||
|
res, err := util.CreateDynamicSecretLease(accessToken, projectSlug, envSlug, secretPath, slug)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Data, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ProcessTemplate(templatePath string, data interface{}, accessToken string, existingEtag string, currentEtag *string) (*bytes.Buffer, error) {
|
func ProcessTemplate(templatePath string, data interface{}, accessToken string, existingEtag string, currentEtag *string) (*bytes.Buffer, error) {
|
||||||
// custom template function to fetch secrets from Infisical
|
// custom template function to fetch secrets from Infisical
|
||||||
secretFunction := secretTemplateFunction(accessToken, existingEtag, currentEtag)
|
secretFunction := secretTemplateFunction(accessToken, existingEtag, currentEtag)
|
||||||
|
dynamicSecretFunction := dynamicSecretTemplateFunction(accessToken)
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{
|
||||||
"secret": secretFunction,
|
"secret": secretFunction,
|
||||||
|
"dynamic_secret": dynamicSecretFunction,
|
||||||
}
|
}
|
||||||
|
|
||||||
templateName := path.Base(templatePath)
|
templateName := path.Base(templatePath)
|
||||||
@@ -266,8 +303,10 @@ func ProcessBase64Template(encodedTemplate string, data interface{}, accessToken
|
|||||||
templateString := string(decoded)
|
templateString := string(decoded)
|
||||||
|
|
||||||
secretFunction := secretTemplateFunction(accessToken, existingEtag, currentEtag) // TODO: Fix this
|
secretFunction := secretTemplateFunction(accessToken, existingEtag, currentEtag) // TODO: Fix this
|
||||||
|
dynamicSecretFunction := dynamicSecretTemplateFunction(accessToken)
|
||||||
funcs := template.FuncMap{
|
funcs := template.FuncMap{
|
||||||
"secret": secretFunction,
|
"secret": secretFunction,
|
||||||
|
"dynamic_secret": dynamicSecretFunction,
|
||||||
}
|
}
|
||||||
|
|
||||||
templateName := "base64Template"
|
templateName := "base64Template"
|
||||||
@@ -285,7 +324,7 @@ func ProcessBase64Template(encodedTemplate string, data interface{}, accessToken
|
|||||||
return &buf, nil
|
return &buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenManager struct {
|
type AgentManager struct {
|
||||||
accessToken string
|
accessToken string
|
||||||
accessTokenTTL time.Duration
|
accessTokenTTL time.Duration
|
||||||
accessTokenMaxTTL time.Duration
|
accessTokenMaxTTL time.Duration
|
||||||
@@ -294,6 +333,7 @@ type TokenManager struct {
|
|||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
filePaths []Sink // Store file paths if needed
|
filePaths []Sink // Store file paths if needed
|
||||||
templates []Template
|
templates []Template
|
||||||
|
dynamicSecretLeases []DynamicSecretLeaseManger
|
||||||
clientIdPath string
|
clientIdPath string
|
||||||
clientSecretPath string
|
clientSecretPath string
|
||||||
newAccessTokenNotificationChan chan bool
|
newAccessTokenNotificationChan chan bool
|
||||||
@@ -302,8 +342,8 @@ type TokenManager struct {
|
|||||||
exitAfterAuth bool
|
exitAfterAuth bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTokenManager(fileDeposits []Sink, templates []Template, clientIdPath string, clientSecretPath string, newAccessTokenNotificationChan chan bool, removeClientSecretOnRead bool, exitAfterAuth bool) *TokenManager {
|
func NewAgentManager(fileDeposits []Sink, templates []Template, clientIdPath string, clientSecretPath string, newAccessTokenNotificationChan chan bool, removeClientSecretOnRead bool, exitAfterAuth bool) *AgentManager {
|
||||||
return &TokenManager{
|
return &AgentManager{
|
||||||
filePaths: fileDeposits,
|
filePaths: fileDeposits,
|
||||||
templates: templates,
|
templates: templates,
|
||||||
clientIdPath: clientIdPath,
|
clientIdPath: clientIdPath,
|
||||||
@@ -315,7 +355,7 @@ func NewTokenManager(fileDeposits []Sink, templates []Template, clientIdPath str
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TokenManager) SetToken(token string, accessTokenTTL time.Duration, accessTokenMaxTTL time.Duration) {
|
func (tm *AgentManager) SetToken(token string, accessTokenTTL time.Duration, accessTokenMaxTTL time.Duration) {
|
||||||
tm.mutex.Lock()
|
tm.mutex.Lock()
|
||||||
defer tm.mutex.Unlock()
|
defer tm.mutex.Unlock()
|
||||||
|
|
||||||
@@ -326,7 +366,7 @@ func (tm *TokenManager) SetToken(token string, accessTokenTTL time.Duration, acc
|
|||||||
tm.newAccessTokenNotificationChan <- true
|
tm.newAccessTokenNotificationChan <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TokenManager) GetToken() string {
|
func (tm *AgentManager) GetToken() string {
|
||||||
tm.mutex.Lock()
|
tm.mutex.Lock()
|
||||||
defer tm.mutex.Unlock()
|
defer tm.mutex.Unlock()
|
||||||
|
|
||||||
@@ -334,7 +374,7 @@ func (tm *TokenManager) GetToken() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetches a new access token using client credentials
|
// Fetches a new access token using client credentials
|
||||||
func (tm *TokenManager) FetchNewAccessToken() error {
|
func (tm *AgentManager) FetchNewAccessToken() error {
|
||||||
clientID := os.Getenv("INFISICAL_UNIVERSAL_AUTH_CLIENT_ID")
|
clientID := os.Getenv("INFISICAL_UNIVERSAL_AUTH_CLIENT_ID")
|
||||||
if clientID == "" {
|
if clientID == "" {
|
||||||
clientIDAsByte, err := ReadFile(tm.clientIdPath)
|
clientIDAsByte, err := ReadFile(tm.clientIdPath)
|
||||||
@@ -384,7 +424,7 @@ func (tm *TokenManager) FetchNewAccessToken() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Refreshes the existing access token
|
// Refreshes the existing access token
|
||||||
func (tm *TokenManager) RefreshAccessToken() error {
|
func (tm *AgentManager) RefreshAccessToken() error {
|
||||||
httpClient := resty.New()
|
httpClient := resty.New()
|
||||||
httpClient.SetRetryCount(10000).
|
httpClient.SetRetryCount(10000).
|
||||||
SetRetryMaxWaitTime(20 * time.Second).
|
SetRetryMaxWaitTime(20 * time.Second).
|
||||||
@@ -405,7 +445,7 @@ func (tm *TokenManager) RefreshAccessToken() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TokenManager) ManageTokenLifecycle() {
|
func (tm *AgentManager) ManageTokenLifecycle() {
|
||||||
for {
|
for {
|
||||||
accessTokenMaxTTLExpiresInTime := tm.accessTokenFetchedTime.Add(tm.accessTokenMaxTTL - (5 * time.Second))
|
accessTokenMaxTTLExpiresInTime := tm.accessTokenFetchedTime.Add(tm.accessTokenMaxTTL - (5 * time.Second))
|
||||||
accessTokenRefreshedTime := tm.accessTokenRefreshedTime
|
accessTokenRefreshedTime := tm.accessTokenRefreshedTime
|
||||||
@@ -473,7 +513,7 @@ func (tm *TokenManager) ManageTokenLifecycle() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TokenManager) WriteTokenToFiles() {
|
func (tm *AgentManager) WriteTokenToFiles() {
|
||||||
token := tm.GetToken()
|
token := tm.GetToken()
|
||||||
for _, sinkFile := range tm.filePaths {
|
for _, sinkFile := range tm.filePaths {
|
||||||
if sinkFile.Type == "file" {
|
if sinkFile.Type == "file" {
|
||||||
@@ -490,7 +530,7 @@ func (tm *TokenManager) WriteTokenToFiles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TokenManager) WriteTemplateToFile(bytes *bytes.Buffer, template *Template) {
|
func (tm *AgentManager) WriteTemplateToFile(bytes *bytes.Buffer, template *Template) {
|
||||||
if err := WriteBytesToFile(bytes, template.DestinationPath); err != nil {
|
if err := WriteBytesToFile(bytes, template.DestinationPath); err != nil {
|
||||||
log.Error().Msgf("template engine: unable to write secrets to path because %s. Will try again on next cycle", err)
|
log.Error().Msgf("template engine: unable to write secrets to path because %s. Will try again on next cycle", err)
|
||||||
return
|
return
|
||||||
@@ -498,7 +538,7 @@ func (tm *TokenManager) WriteTemplateToFile(bytes *bytes.Buffer, template *Templ
|
|||||||
log.Info().Msgf("template engine: secret template at path %s has been rendered and saved to path %s", template.SourcePath, template.DestinationPath)
|
log.Info().Msgf("template engine: secret template at path %s has been rendered and saved to path %s", template.SourcePath, template.DestinationPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *TokenManager) MonitorSecretChanges(secretTemplate Template, sigChan chan os.Signal) {
|
func (tm *AgentManager) MonitorSecretChanges(secretTemplate Template, sigChan chan os.Signal) {
|
||||||
|
|
||||||
pollingInterval := time.Duration(5 * time.Minute)
|
pollingInterval := time.Duration(5 * time.Minute)
|
||||||
|
|
||||||
@@ -645,7 +685,7 @@ var agentCmd = &cobra.Command{
|
|||||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
filePaths := agentConfig.Sinks
|
filePaths := agentConfig.Sinks
|
||||||
tm := NewTokenManager(filePaths, agentConfig.Templates, configUniversalAuthType.ClientIDPath, configUniversalAuthType.ClientSecretPath, tokenRefreshNotifier, configUniversalAuthType.RemoveClientSecretOnRead, agentConfig.Infisical.ExitAfterAuth)
|
tm := NewAgentManager(filePaths, agentConfig.Templates, configUniversalAuthType.ClientIDPath, configUniversalAuthType.ClientSecretPath, tokenRefreshNotifier, configUniversalAuthType.RemoveClientSecretOnRead, agentConfig.Infisical.ExitAfterAuth)
|
||||||
|
|
||||||
go tm.ManageTokenLifecycle()
|
go tm.ManageTokenLifecycle()
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,23 @@ type PlaintextSecretResult struct {
|
|||||||
Etag string
|
Etag string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DynamicSecret struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
DefaultTTL string `json:"defaultTTL"`
|
||||||
|
MaxTTL string `json:"maxTTL"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DynamicSecretLease struct {
|
||||||
|
Lease struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
ExpireAt string `json:"expireAt"`
|
||||||
|
} `json:"lease"`
|
||||||
|
DynamicSecret DynamicSecret `json:"dynamicSecret"`
|
||||||
|
// this is a varying dict based on provider
|
||||||
|
Data map[string]interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
type SingleFolder struct {
|
type SingleFolder struct {
|
||||||
ID string `json:"_id"`
|
ID string `json:"_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|||||||
@@ -195,6 +195,29 @@ func GetPlainTextSecretsViaMachineIdentity(accessToken string, workspaceId strin
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateDynamicSecretLease(accessToken string, projectSlug string, environmentName string, secretsPath string, slug string) (models.DynamicSecretLease, error) {
|
||||||
|
httpClient := resty.New()
|
||||||
|
httpClient.SetAuthToken(accessToken).
|
||||||
|
SetHeader("Accept", "application/json")
|
||||||
|
|
||||||
|
dynamicSecretRequest := api.CreateDynamicSecretLeaseV1Request{
|
||||||
|
ProjectSlug: projectSlug,
|
||||||
|
Environment: environmentName,
|
||||||
|
Slug: slug,
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicSecret, err := api.CallCreateDynamicSecretLeaseV1(httpClient, dynamicSecretRequest)
|
||||||
|
if err != nil {
|
||||||
|
return models.DynamicSecretLease{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return models.DynamicSecretLease{
|
||||||
|
Lease: dynamicSecret.Lease,
|
||||||
|
Data: dynamicSecret.Data,
|
||||||
|
DynamicSecret: dynamicSecret.DynamicSecret,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func InjectImportedSecret(plainTextWorkspaceKey []byte, secrets []models.SingleEnvironmentVariable, importedSecrets []api.ImportedSecretV3) ([]models.SingleEnvironmentVariable, error) {
|
func InjectImportedSecret(plainTextWorkspaceKey []byte, secrets []models.SingleEnvironmentVariable, importedSecrets []api.ImportedSecretV3) ([]models.SingleEnvironmentVariable, error) {
|
||||||
if importedSecrets == nil {
|
if importedSecrets == nil {
|
||||||
return secrets, nil
|
return secrets, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user