Merge pull request #2740 from akhilmhdh/feat/dynamic-secret-cli

Dynamic secret commands in CLI
This commit is contained in:
Akhil Mohan
2024-11-27 14:07:40 +05:30
committed by GitHub
10 changed files with 967 additions and 5 deletions

View File

@ -112,7 +112,7 @@ export const dynamicSecretLeaseServiceFactory = ({
})
) as object;
const selectedTTL = ttl ?? dynamicSecretCfg.defaultTTL;
const selectedTTL = ttl || dynamicSecretCfg.defaultTTL;
const { maxTTL } = dynamicSecretCfg;
const expireAt = new Date(new Date().getTime() + ms(selectedTTL));
if (maxTTL) {
@ -187,7 +187,7 @@ export const dynamicSecretLeaseServiceFactory = ({
})
) as object;
const selectedTTL = ttl ?? dynamicSecretCfg.defaultTTL;
const selectedTTL = ttl || dynamicSecretCfg.defaultTTL;
const { maxTTL } = dynamicSecretCfg;
const expireAt = new Date(dynamicSecretLease.expireAt.getTime() + ms(selectedTTL));
if (maxTTL) {

View File

@ -10,7 +10,7 @@ require (
github.com/fatih/semgroup v1.2.0
github.com/gitleaks/go-gitdiff v0.8.0
github.com/h2non/filetype v1.1.3
github.com/infisical/go-sdk v0.3.8
github.com/infisical/go-sdk v0.4.3
github.com/mattn/go-isatty v0.0.20
github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a
github.com/muesli/mango-cobra v1.2.0

View File

@ -265,8 +265,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/infisical/go-sdk v0.3.8 h1:0dGOhF3cwt0q5QzpnUs4lxwBiEza+DQYOyvEn7AfrM0=
github.com/infisical/go-sdk v0.3.8/go.mod h1:HHW7DgUqoolyQIUw/9HdpkZ3bDLwWyZ0HEtYiVaDKQw=
github.com/infisical/go-sdk v0.4.3 h1:O5ZJ2eCBAZDE9PIAfBPq9Utb2CgQKrhmj9R0oFTRu4U=
github.com/infisical/go-sdk v0.4.3/go.mod h1:6fWzAwTPIoKU49mQ2Oxu+aFnJu9n7k2JcNrZjzhHM2M=
github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=

View File

@ -205,6 +205,25 @@ func CallGetAllWorkSpacesUserBelongsTo(httpClient *resty.Client) (GetWorkSpacesR
return workSpacesResponse, nil
}
func CallGetProjectById(httpClient *resty.Client, id string) (Project, error) {
var projectResponse GetProjectByIdResponse
response, err := httpClient.
R().
SetResult(&projectResponse).
SetHeader("User-Agent", USER_AGENT).
Get(fmt.Sprintf("%v/v1/workspace/%s", config.INFISICAL_URL, id))
if err != nil {
return Project{}, err
}
if response.IsError() {
return Project{}, fmt.Errorf("CallGetProjectById: Unsuccessful response: [response=%v]", response)
}
return projectResponse.Project, nil
}
func CallIsAuthenticated(httpClient *resty.Client) bool {
var workSpacesResponse GetWorkSpacesResponse
response, err := httpClient.

View File

@ -128,6 +128,10 @@ type GetWorkSpacesResponse struct {
} `json:"workspaces"`
}
type GetProjectByIdResponse struct {
Project Project `json:"workspace"`
}
type GetOrganizationsResponse struct {
Organizations []struct {
ID string `json:"id"`
@ -163,6 +167,12 @@ type Secret struct {
PlainTextKey string `json:"plainTextKey"`
}
type Project struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
}
type RawSecret struct {
SecretKey string `json:"secretKey,omitempty"`
SecretValue string `json:"secretValue,omitempty"`

View File

@ -0,0 +1,571 @@
/*
Copyright (c) 2023 Infisical Inc.
*/
package cmd
import (
"context"
"fmt"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/config"
"github.com/Infisical/infisical-merge/packages/visualize"
// "github.com/Infisical/infisical-merge/packages/models"
"github.com/Infisical/infisical-merge/packages/util"
// "github.com/Infisical/infisical-merge/packages/visualize"
"github.com/go-resty/resty/v2"
"github.com/posthog/posthog-go"
"github.com/spf13/cobra"
infisicalSdk "github.com/infisical/go-sdk"
infisicalSdkModels "github.com/infisical/go-sdk/packages/models"
)
var dynamicSecretCmd = &cobra.Command{
Example: `infisical dynamic-secrets`,
Short: "Used to list dynamic secrets",
Use: "dynamic-secrets",
DisableFlagsInUseLine: true,
Args: cobra.NoArgs,
Run: getDynamicSecretList,
}
func getDynamicSecretList(cmd *cobra.Command, args []string) {
environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") {
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
if environmentFromWorkspace != "" {
environmentName = environmentFromWorkspace
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse path flag")
}
var infisicalToken string
httpClient := resty.New()
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
projectId = workspaceFile.WorkspaceId
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
infisicalToken = token.Token
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
infisicalToken = loggedInUserDetails.UserCredentials.JTWToken
}
httpClient.SetAuthToken(infisicalToken)
infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{
SiteUrl: config.INFISICAL_URL,
UserAgent: api.USER_AGENT,
AutoTokenRefresh: false,
})
infisicalClient.Auth().SetAccessToken(infisicalToken)
projectDetails, err := api.CallGetProjectById(httpClient, projectId)
if err != nil {
util.HandleError(err, "To fetch project details")
}
dynamicSecretRootCredentials, err := infisicalClient.DynamicSecrets().List(infisicalSdk.ListDynamicSecretsRootCredentialsOptions{
ProjectSlug: projectDetails.Slug,
SecretPath: secretsPath,
EnvironmentSlug: environmentName,
})
if err != nil {
util.HandleError(err, "To fetch dynamic secret root credentials details")
}
visualize.PrintAllDynamicRootCredentials(dynamicSecretRootCredentials)
Telemetry.CaptureEvent("cli-command:dynamic-secrets", posthog.NewProperties().Set("count", len(dynamicSecretRootCredentials)).Set("version", util.CLI_VERSION))
}
var dynamicSecretLeaseCmd = &cobra.Command{
Example: `lease`,
Short: "Manage leases for dynamic secrets",
Use: "lease",
DisableFlagsInUseLine: true,
}
var dynamicSecretLeaseCreateCmd = &cobra.Command{
Example: `lease create <dynamic secret name>"`,
Short: "Used to lease dynamic secret by name",
Use: "create [dynamic-secret]",
DisableFlagsInUseLine: true,
Args: cobra.ExactArgs(1),
Run: createDynamicSecretLeaseByName,
}
func createDynamicSecretLeaseByName(cmd *cobra.Command, args []string) {
dynamicSecretRootCredentialName := args[0]
environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") {
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
if environmentFromWorkspace != "" {
environmentName = environmentFromWorkspace
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
ttl, err := cmd.Flags().GetString("ttl")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse path flag")
}
plainOutput, err := cmd.Flags().GetBool("plain")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
var infisicalToken string
httpClient := resty.New()
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
projectId = workspaceFile.WorkspaceId
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
infisicalToken = token.Token
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
infisicalToken = loggedInUserDetails.UserCredentials.JTWToken
}
httpClient.SetAuthToken(infisicalToken)
infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{
SiteUrl: config.INFISICAL_URL,
UserAgent: api.USER_AGENT,
AutoTokenRefresh: false,
})
infisicalClient.Auth().SetAccessToken(infisicalToken)
projectDetails, err := api.CallGetProjectById(httpClient, projectId)
if err != nil {
util.HandleError(err, "To fetch project details")
}
dynamicSecretRootCredential, err := infisicalClient.DynamicSecrets().GetByName(infisicalSdk.GetDynamicSecretRootCredentialByNameOptions{
DynamicSecretName: dynamicSecretRootCredentialName,
ProjectSlug: projectDetails.Slug,
SecretPath: secretsPath,
EnvironmentSlug: environmentName,
})
if err != nil {
util.HandleError(err, "To fetch dynamic secret root credentials details")
}
leaseCredentials, _, leaseDetails, err := infisicalClient.DynamicSecrets().Leases().Create(infisicalSdk.CreateDynamicSecretLeaseOptions{
DynamicSecretName: dynamicSecretRootCredential.Name,
ProjectSlug: projectDetails.Slug,
TTL: ttl,
SecretPath: secretsPath,
EnvironmentSlug: environmentName,
})
if err != nil {
util.HandleError(err, "To lease dynamic secret")
}
if plainOutput {
for key, value := range leaseCredentials {
if cred, ok := value.(string); ok {
fmt.Printf("%s=%s\n", key, cred)
}
}
} else {
fmt.Println("Dynamic Secret Leasing")
fmt.Printf("Name: %s\n", dynamicSecretRootCredential.Name)
fmt.Printf("Provider: %s\n", dynamicSecretRootCredential.Type)
fmt.Printf("Lease ID: %s\n", leaseDetails.Id)
fmt.Printf("Expire At: %s\n", leaseDetails.ExpireAt.Local().Format("02-Jan-2006 03:04:05 PM"))
visualize.PrintAllDyamicSecretLeaseCredentials(leaseCredentials)
}
Telemetry.CaptureEvent("cli-command:dynamic-secrets lease", posthog.NewProperties().Set("type", dynamicSecretRootCredential.Type).Set("version", util.CLI_VERSION))
}
var dynamicSecretLeaseRenewCmd = &cobra.Command{
Example: `lease renew <dynamic secret name>"`,
Short: "Used to renew dynamic secret lease by name",
Use: "renew [lease-id]",
DisableFlagsInUseLine: true,
Args: cobra.ExactArgs(1),
Run: renewDynamicSecretLeaseByName,
}
func renewDynamicSecretLeaseByName(cmd *cobra.Command, args []string) {
dynamicSecretLeaseId := args[0]
environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") {
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
if environmentFromWorkspace != "" {
environmentName = environmentFromWorkspace
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
ttl, err := cmd.Flags().GetString("ttl")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse path flag")
}
var infisicalToken string
httpClient := resty.New()
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
projectId = workspaceFile.WorkspaceId
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
infisicalToken = token.Token
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
infisicalToken = loggedInUserDetails.UserCredentials.JTWToken
}
httpClient.SetAuthToken(infisicalToken)
infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{
SiteUrl: config.INFISICAL_URL,
UserAgent: api.USER_AGENT,
AutoTokenRefresh: false,
})
infisicalClient.Auth().SetAccessToken(infisicalToken)
projectDetails, err := api.CallGetProjectById(httpClient, projectId)
if err != nil {
util.HandleError(err, "To fetch project details")
}
if err != nil {
util.HandleError(err, "To fetch dynamic secret root credentials details")
}
leaseDetails, err := infisicalClient.DynamicSecrets().Leases().RenewById(infisicalSdk.RenewDynamicSecretLeaseOptions{
ProjectSlug: projectDetails.Slug,
TTL: ttl,
SecretPath: secretsPath,
EnvironmentSlug: environmentName,
LeaseId: dynamicSecretLeaseId,
})
if err != nil {
util.HandleError(err, "To renew dynamic secret lease")
}
fmt.Println("Successfully renewed dynamic secret lease")
visualize.PrintAllDynamicSecretLeases([]infisicalSdkModels.DynamicSecretLease{leaseDetails})
Telemetry.CaptureEvent("cli-command:dynamic-secrets lease renew", posthog.NewProperties().Set("version", util.CLI_VERSION))
}
var dynamicSecretLeaseRevokeCmd = &cobra.Command{
Example: `lease delete <dynamic secret name>"`,
Short: "Used to delete dynamic secret lease by name",
Use: "delete [lease-id]",
DisableFlagsInUseLine: true,
Args: cobra.ExactArgs(1),
Run: revokeDynamicSecretLeaseByName,
}
func revokeDynamicSecretLeaseByName(cmd *cobra.Command, args []string) {
dynamicSecretLeaseId := args[0]
environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") {
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
if environmentFromWorkspace != "" {
environmentName = environmentFromWorkspace
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse path flag")
}
var infisicalToken string
httpClient := resty.New()
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
projectId = workspaceFile.WorkspaceId
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
infisicalToken = token.Token
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
infisicalToken = loggedInUserDetails.UserCredentials.JTWToken
}
httpClient.SetAuthToken(infisicalToken)
infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{
SiteUrl: config.INFISICAL_URL,
UserAgent: api.USER_AGENT,
AutoTokenRefresh: false,
})
infisicalClient.Auth().SetAccessToken(infisicalToken)
projectDetails, err := api.CallGetProjectById(httpClient, projectId)
if err != nil {
util.HandleError(err, "To fetch project details")
}
if err != nil {
util.HandleError(err, "To fetch dynamic secret root credentials details")
}
leaseDetails, err := infisicalClient.DynamicSecrets().Leases().DeleteById(infisicalSdk.DeleteDynamicSecretLeaseOptions{
ProjectSlug: projectDetails.Slug,
SecretPath: secretsPath,
EnvironmentSlug: environmentName,
LeaseId: dynamicSecretLeaseId,
})
if err != nil {
util.HandleError(err, "To revoke dynamic secret lease")
}
fmt.Println("Successfully revoked dynamic secret lease")
visualize.PrintAllDynamicSecretLeases([]infisicalSdkModels.DynamicSecretLease{leaseDetails})
Telemetry.CaptureEvent("cli-command:dynamic-secrets lease revoke", posthog.NewProperties().Set("version", util.CLI_VERSION))
}
var dynamicSecretLeaseListCmd = &cobra.Command{
Example: `lease list <dynamic secret name>"`,
Short: "Used to list leases of a dynamic secret by name",
Use: "list [dynamic-secret]",
DisableFlagsInUseLine: true,
Args: cobra.ExactArgs(1),
Run: listDynamicSecretLeaseByName,
}
func listDynamicSecretLeaseByName(cmd *cobra.Command, args []string) {
dynamicSecretRootCredentialName := args[0]
environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") {
environmentFromWorkspace := util.GetEnvFromWorkspaceFile()
if environmentFromWorkspace != "" {
environmentName = environmentFromWorkspace
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse path flag")
}
var infisicalToken string
httpClient := resty.New()
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
projectId = workspaceFile.WorkspaceId
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
infisicalToken = token.Token
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
infisicalToken = loggedInUserDetails.UserCredentials.JTWToken
}
httpClient.SetAuthToken(infisicalToken)
infisicalClient := infisicalSdk.NewInfisicalClient(context.Background(), infisicalSdk.Config{
SiteUrl: config.INFISICAL_URL,
UserAgent: api.USER_AGENT,
AutoTokenRefresh: false,
})
infisicalClient.Auth().SetAccessToken(infisicalToken)
projectDetails, err := api.CallGetProjectById(httpClient, projectId)
if err != nil {
util.HandleError(err, "To fetch project details")
}
dynamicSecretLeases, err := infisicalClient.DynamicSecrets().Leases().List(infisicalSdk.ListDynamicSecretLeasesOptions{
DynamicSecretName: dynamicSecretRootCredentialName,
ProjectSlug: projectDetails.Slug,
SecretPath: secretsPath,
EnvironmentSlug: environmentName,
})
if err != nil {
util.HandleError(err, "To fetch dynamic secret leases list")
}
visualize.PrintAllDynamicSecretLeases(dynamicSecretLeases)
Telemetry.CaptureEvent("cli-command:dynamic-secrets lease list", posthog.NewProperties().Set("lease-count", len(dynamicSecretLeases)).Set("version", util.CLI_VERSION))
}
func init() {
dynamicSecretLeaseCreateCmd.Flags().StringP("path", "p", "/", "The path from where dynamic secret should be leased from")
dynamicSecretLeaseCreateCmd.Flags().String("token", "", "Create dynamic secret leases using machine identity access token")
dynamicSecretLeaseCreateCmd.Flags().String("projectId", "", "Manually set the projectId to fetch leased from when using machine identity based auth")
dynamicSecretLeaseCreateCmd.Flags().String("ttl", "", "The lease lifetime TTL. If not provided the default TTL of dynamic secret will be used.")
dynamicSecretLeaseCreateCmd.Flags().Bool("plain", false, "Print leased credentials without formatting, one per line")
dynamicSecretLeaseCmd.AddCommand(dynamicSecretLeaseCreateCmd)
dynamicSecretLeaseListCmd.Flags().StringP("path", "p", "/", "The path from where dynamic secret should be leased from")
dynamicSecretLeaseListCmd.Flags().String("token", "", "Fetch dynamic secret leases machine identity access token")
dynamicSecretLeaseListCmd.Flags().String("projectId", "", "Manually set the projectId to fetch leased from when using machine identity based auth")
dynamicSecretLeaseCmd.AddCommand(dynamicSecretLeaseListCmd)
dynamicSecretLeaseRenewCmd.Flags().StringP("path", "p", "/", "The path from where dynamic secret should be leased from")
dynamicSecretLeaseRenewCmd.Flags().String("token", "", "Renew dynamic secrets machine identity access token")
dynamicSecretLeaseRenewCmd.Flags().String("projectId", "", "Manually set the projectId to fetch leased from when using machine identity based auth")
dynamicSecretLeaseRenewCmd.Flags().String("ttl", "", "The lease lifetime TTL. If not provided the default TTL of dynamic secret will be used.")
dynamicSecretLeaseCmd.AddCommand(dynamicSecretLeaseRenewCmd)
dynamicSecretLeaseRevokeCmd.Flags().StringP("path", "p", "/", "The path from where dynamic secret should be leased from")
dynamicSecretLeaseRevokeCmd.Flags().String("token", "", "Delete dynamic secrets using machine identity access token")
dynamicSecretLeaseRevokeCmd.Flags().String("projectId", "", "Manually set the projectId to fetch leased from when using machine identity based auth")
dynamicSecretLeaseCmd.AddCommand(dynamicSecretLeaseRevokeCmd)
dynamicSecretCmd.AddCommand(dynamicSecretLeaseCmd)
dynamicSecretCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
dynamicSecretCmd.Flags().String("projectId", "", "Manually set the projectId to fetch dynamic-secret when using machine identity based auth")
dynamicSecretCmd.PersistentFlags().String("env", "dev", "Used to select the environment name on which actions should be taken on")
dynamicSecretCmd.Flags().String("path", "/", "get dynamic secret within a folder path")
rootCmd.AddCommand(dynamicSecretCmd)
}

View File

@ -0,0 +1,39 @@
package visualize
import infisicalModels "github.com/infisical/go-sdk/packages/models"
func PrintAllDyamicSecretLeaseCredentials(leaseCredentials map[string]any) {
rows := [][]string{}
for key, value := range leaseCredentials {
if cred, ok := value.(string); ok {
rows = append(rows, []string{key, cred})
}
}
headers := []string{"Key", "Value"}
GenericTable(headers, rows)
}
func PrintAllDynamicRootCredentials(dynamicRootCredentials []infisicalModels.DynamicSecret) {
rows := [][]string{}
for _, el := range dynamicRootCredentials {
rows = append(rows, []string{el.Name, el.Type, el.DefaultTTL, el.MaxTTL})
}
headers := []string{"Name", "Provider", "Default TTL", "Max TTL"}
GenericTable(headers, rows)
}
func PrintAllDynamicSecretLeases(dynamicSecretLeases []infisicalModels.DynamicSecretLease) {
rows := [][]string{}
const timeformat = "02-Jan-2006 03:04:05 PM"
for _, el := range dynamicSecretLeases {
rows = append(rows, []string{el.Id, el.ExpireAt.Local().Format(timeformat), el.CreatedAt.Local().Format(timeformat)})
}
headers := []string{"ID", "Expire At", "Created At"}
GenericTable(headers, rows)
}

View File

@ -94,6 +94,33 @@ func getLongestValues(rows [][3]string) (longestSecretName, longestSecretType in
return
}
func GenericTable(headers []string, rows [][]string) {
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SetStyle(table.StyleLight)
// t.SetTitle(tableOptions.Title)
t.Style().Options.DrawBorder = true
t.Style().Options.SeparateHeader = true
t.Style().Options.SeparateColumns = true
tableHeaders := table.Row{}
for _, header := range headers {
tableHeaders = append(tableHeaders, header)
}
t.AppendHeader(tableHeaders)
for _, row := range rows {
tableRow := table.Row{}
for _, val := range row {
tableRow = append(tableRow, val)
}
t.AppendRow(tableRow)
}
t.Render()
}
// stringWidth returns the width of a string.
// ANSI escape sequences are ignored and double-width characters are handled correctly.
func stringWidth(str string) (width int) {

View File

@ -0,0 +1,295 @@
---
title: "infisical dynamic-secrets"
description: "Perform dynamic secret operations directly with the CLI"
---
```
infisical dynamic-secrets
```
## Description
Dynamic secrets are unique secrets generated on demand based on the provided configuration settings. For more details, refer to [dynamics secrets section](/documentation/platform/dynamic-secrets/overview).
This command enables you to perform list, lease, renew lease, and revoke lease operations on dynamic secrets within your Infisical project.
### Sub-commands
<Accordion title="infisical dynamic-secrets">
Use this command to print out all of the dynamic secrets in your project.
```bash
$ infisical dynamic-secrets
```
### Environment variables
<Accordion title="INFISICAL_TOKEN">
Used to fetch dynamic secrets via a [machine identity](/documentation/platform/identities/machine-identities) instead of logged-in credentials. Simply, export this variable in the terminal before running this command.
```bash
# Example
export INFISICAL_TOKEN=$(infisical login --method=universal-auth --client-id=<identity-client-id> --client-secret=<identity-client-secret> --silent --plain) # --plain flag will output only the token, so it can be fed to an environment variable. --silent will disable any update messages.
```
</Accordion>
<Accordion title="INFISICAL_DISABLE_UPDATE_CHECK">
Used to disable the check for new CLI versions. This can improve the time it takes to run this command. Recommended for production environments.
To use, simply export this variable in the terminal before running this command.
```bash
# Example
export INFISICAL_DISABLE_UPDATE_CHECK=true
```
</Accordion>
### Flags
<Accordion title="--projectId">
The project ID to fetch dynamic secrets from. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets --projectId=<project-id>
```
</Accordion>
<Accordion title="--token">
The authenticated token to fetch dynamic secrets from. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets --token=<token>
```
</Accordion>
<Accordion title="--env">
Used to select the environment name on which actions should be taken. Default
value: `dev`
</Accordion>
<Accordion title="--path">
Use to select the project folder on which dynamic secrets will be accessed.
```bash
# Example
infisical dynamic-secrets --path="/" --env=dev
```
</Accordion>
</Accordion>
<Accordion title="infisical dynamic-secrets lease create">
This command is used to create a new lease for a dynamic secret.
```bash
$ infisical dynamic-secrets lease create <dynamic-secret-name>
```
### Flags
<Accordion title="--env">
Used to select the environment name on which actions should be taken. Default
value: `dev`
</Accordion>
<Accordion title="--plain">
The `--plain` flag will output dynamic secret lease credentials values without formatting, one per line.
Default value: `false`
```bash
# Example
infisical dynamic-secrets lease create dynamic-secret-postgres --plain
```
</Accordion>
<Accordion title="--path">
The `--path` flag indicates which project folder dynamic secrets will be injected from.
```bash
# Example
infisical dynamic-secrets lease create <dynamic-secret-name> --path="/" --env=dev
```
</Accordion>
<Accordion title="--projectId">
The project ID of the dynamic secrets to lease from. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease create <dynamic-secret-name> --projectId=<project-id>
```
</Accordion>
<Accordion title="--token">
The authenticated token to create dynamic secret leases. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease create <dynamic-secret-name> --token=<token>
```
</Accordion>
<Accordion title="--ttl">
The lease lifetime. If not provided, the default TTL of the dynamic secret root credential will be used.
```bash
# Example
infisical dynamic-secrets lease create <dynamic-secret-name> --ttl=<ttl>
```
</Accordion>
</Accordion>
<Accordion title="infisical dynamic-secrets lease list">
This command is used to list leases for a dynamic secret.
```bash
$ infisical dynamic-secrets lease list <dynamic-secret-name>
```
### Flags
<Accordion title="--env">
Used to select the environment name on which actions should be taken. Default
value: `dev`
</Accordion>
<Accordion title="--path">
The `--path` flag indicates which project folder dynamic secrets will be injected from.
```bash
# Example
infisical dynamic-secrets lease list <dynamic-secret-name> --path="/" --env=dev
```
</Accordion>
<Accordion title="--projectId">
The project ID of the dynamic secrets to list leases from. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease list <dynamic-secret-name> --projectId=<project-id>
```
</Accordion>
<Accordion title="--token">
The authenticated token to list dynamic secret leases. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease list <dynamic-secret-name> --token=<token>
```
</Accordion>
</Accordion>
<Accordion title="infisical dynamic-secrets lease renew">
This command is used to renew a lease before it expires.
```bash
$ infisical dynamic-secrets lease renew <lease-id>
```
### Flags
<Accordion title="--env">
Used to select the environment name on which actions should be taken. Default
value: `dev`
</Accordion>
<Accordion title="--path">
The `--path` flag indicates which project folder dynamic secrets will be renewed from.
```bash
# Example
infisical dynamic-secrets lease renew <lease-id> --path="/" --env=dev
```
</Accordion>
<Accordion title="--projectId">
The project ID of the dynamic secret's lease from. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease renew <lease-id> --projectId=<project-id>
```
</Accordion>
<Accordion title="--token">
The authenticated token to create dynamic secret leases. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease renew <lease-id> --token=<token>
```
</Accordion>
<Accordion title="--ttl">
The lease lifetime. If not provided, the default TTL of the dynamic secret root credential will be used.
```bash
# Example
infisical dynamic-secrets lease renew <lease-id> --ttl=<ttl>
```
</Accordion>
</Accordion>
<Accordion title="infisical dynamic-secrets lease delete">
This command is used to delete a lease.
```bash
$ infisical dynamic-secrets lease delete <lease-id>
```
### Flags
<Accordion title="--env">
Used to select the environment name on which actions should be taken. Default
value: `dev`
</Accordion>
<Accordion title="--path">
The `--path` flag indicates which project folder dynamic secrets will be deleted from.
```bash
# Example
infisical dynamic-secrets lease delete <lease-id> --path="/" --env=dev
```
</Accordion>
<Accordion title="--projectId">
The project ID of the dynamic secret's lease from. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease delete <lease-id> --projectId=<project-id>
```
</Accordion>
<Accordion title="--token">
The authenticated token to delete dynamic secret leases. This is required when using a machine identity to authenticate.
```bash
# Example
infisical dynamic-secrets lease delete <lease-id> --token=<token>
```
</Accordion>
</Accordion>

View File

@ -316,6 +316,7 @@
"cli/commands/init",
"cli/commands/run",
"cli/commands/secrets",
"cli/commands/dynamic-secrets",
"cli/commands/export",
"cli/commands/token",
"cli/commands/service-token",