mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-25 14:05:03 +00:00
Merge pull request #2740 from akhilmhdh/feat/dynamic-secret-cli
Dynamic secret commands in CLI
This commit is contained in:
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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=
|
||||
|
@ -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.
|
||||
|
@ -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"`
|
||||
|
571
cli/packages/cmd/dynamic_secrets.go
Normal file
571
cli/packages/cmd/dynamic_secrets.go
Normal 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)
|
||||
}
|
39
cli/packages/visualize/dynamic_secret_leases.go
Normal file
39
cli/packages/visualize/dynamic_secret_leases.go
Normal 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)
|
||||
}
|
@ -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) {
|
||||
|
295
docs/cli/commands/dynamic-secrets.mdx
Normal file
295
docs/cli/commands/dynamic-secrets.mdx
Normal 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>
|
@ -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",
|
||||
|
Reference in New Issue
Block a user