diff --git a/cli/agent-config.yaml b/cli/agent-config.yaml index e767fdca52..210c21413a 100644 --- a/cli/agent-config.yaml +++ b/cli/agent-config.yaml @@ -11,12 +11,25 @@ sinks: config: path: "access-token" templates: - - source-path: my-dot-ev-secret-template + - template-content: | + {{- with secret "202f04d7-e4cb-43d4-a292-e893712d61fc" "dev" "/" }} + {{- range . }} + {{ .Key }}={{ .Value }} + {{- end }} + {{- end }} + destination-path: my-dot-env-0.env + config: + polling-interval: 60s + execute: + command: docker-compose -f docker-compose.prod.yml down && docker-compose -f docker-compose.prod.yml up -d + + - base64-template-content: e3stIHdpdGggc2VjcmV0ICIyMDJmMDRkNy1lNGNiLTQzZDQtYTI5Mi1lODkzNzEyZDYxZmMiICJkZXYiICIvIiB9fQp7ey0gcmFuZ2UgLiB9fQp7eyAuS2V5IH19PXt7IC5WYWx1ZSB9fQp7ey0gZW5kIH19Cnt7LSBlbmQgfX0= destination-path: my-dot-env.env config: polling-interval: 60s execute: command: docker-compose -f docker-compose.prod.yml down && docker-compose -f docker-compose.prod.yml up -d + - source-path: my-dot-ev-secret-template1 destination-path: my-dot-env-1.env config: diff --git a/cli/packages/cmd/agent.go b/cli/packages/cmd/agent.go index 0c99377ae0..118aca119d 100644 --- a/cli/packages/cmd/agent.go +++ b/cli/packages/cmd/agent.go @@ -95,6 +95,7 @@ type Template struct { SourcePath string `yaml:"source-path"` Base64TemplateContent string `yaml:"base64-template-content"` DestinationPath string `yaml:"destination-path"` + TemplateContent string `yaml:"template-content"` Config struct { // Configurations for the template PollingInterval string `yaml:"polling-interval"` // How often to poll for changes in the secret @@ -432,6 +433,30 @@ func ProcessBase64Template(templateId int, encodedTemplate string, data interfac return &buf, nil } +func ProcessLiteralTemplate(templateId int, templateString string, data interface{}, accessToken string, existingEtag string, currentEtag *string, dynamicSecretLeaser *DynamicSecretLeaseManager) (*bytes.Buffer, error) { + secretFunction := secretTemplateFunction(accessToken, existingEtag, currentEtag) // TODO: Fix this + dynamicSecretFunction := dynamicSecretTemplateFunction(accessToken, dynamicSecretLeaser, templateId) + funcs := template.FuncMap{ + "secret": secretFunction, + "dynamic_secret": dynamicSecretFunction, + } + + templateName := "literalTemplate" + + tmpl, err := template.New(templateName).Funcs(funcs).Parse(templateString) + if err != nil { + return nil, err + } + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, data); err != nil { + return nil, err + } + + return &buf, nil +} + + type AgentManager struct { accessToken string accessTokenTTL time.Duration @@ -820,6 +845,8 @@ func (tm *AgentManager) MonitorSecretChanges(secretTemplate Template, templateId if secretTemplate.SourcePath != "" { processedTemplate, err = ProcessTemplate(templateId, secretTemplate.SourcePath, nil, token, existingEtag, ¤tEtag, tm.dynamicSecretLeases) + } else if secretTemplate.TemplateContent != "" { + processedTemplate, err = ProcessLiteralTemplate(templateId, secretTemplate.TemplateContent, nil, token, existingEtag, ¤tEtag, tm.dynamicSecretLeases) } else { processedTemplate, err = ProcessBase64Template(templateId, secretTemplate.Base64TemplateContent, nil, token, existingEtag, ¤tEtag, tm.dynamicSecretLeases) } diff --git a/docs/integrations/platforms/infisical-agent.mdx b/docs/integrations/platforms/infisical-agent.mdx index 93c82f8feb..cba70e6021 100644 --- a/docs/integrations/platforms/infisical-agent.mdx +++ b/docs/integrations/platforms/infisical-agent.mdx @@ -9,56 +9,60 @@ It eliminates the need to modify application logic by enabling clients to decide ![agent diagram](/images/agent/infisical-agent-diagram.png) ### Key features: + - Token renewal: Automatically authenticates with Infisical and deposits renewed access tokens at specified path for applications to consume - Templating: Renders secrets via user provided templates to desired formats for applications to consume ### Token renewal + The Infisical agent can help manage the life cycle of access tokens. The token renewal process is split into two main components: a `Method`, which is the authentication process suitable for your current setup, and `Sinks`, which are the places where the agent deposits the new access token whenever it receives updates. -When the Infisical Agent is started, it will attempt to obtain a valid access token using the authentication method you have configured. If the agent is unable to fetch a valid token, the agent will keep trying, increasing the time between each attempt. +When the Infisical Agent is started, it will attempt to obtain a valid access token using the authentication method you have configured. If the agent is unable to fetch a valid token, the agent will keep trying, increasing the time between each attempt. Once a access token is successfully fetched, the agent will make sure the access token stays valid, continuing to renew it before it expires. Every time the agent successfully retrieves a new access token, it writes the new token to the Sinks you've configured. - Access tokens can be utilized with Infisical SDKs or directly in API requests to retrieve secrets from Infisical + Access tokens can be utilized with Infisical SDKs or directly in API requests + to retrieve secrets from Infisical ### Templating -The Infisical agent can help deliver formatted secrets to your application in a variety of environments. To achieve this, the agent will retrieve secrets from Infisical, format them using a specified template, and then save these formatted secrets to a designated file path. -Templating process is done through the use of Go language's [text/template feature](https://pkg.go.dev/text/template). Multiple template definitions can be set in the agent configuration file to generate a variety of formatted secret files. +The Infisical agent can help deliver formatted secrets to your application in a variety of environments. To achieve this, the agent will retrieve secrets from Infisical, format them using a specified template, and then save these formatted secrets to a designated file path. + +Templating process is done through the use of Go language's [text/template feature](https://pkg.go.dev/text/template).You can refer to the available secret template functions [here](#available-secret-template-functions). Multiple template definitions can be set in the agent configuration file to generate a variety of formatted secret files. -When the agent is started and templates are defined in the agent configuration file, the agent will attempt to acquire a valid access token using the set authentication method outlined in the agent's configuration. +When the agent is started and templates are defined in the agent configuration file, the agent will attempt to acquire a valid access token using the set authentication method outlined in the agent's configuration. If this initial attempt is unsuccessful, the agent will momentarily pauses before continuing to make more attempts. -Once the agent successfully obtains a valid access token, the agent proceeds to fetch the secrets from Infisical using it. +Once the agent successfully obtains a valid access token, the agent proceeds to fetch the secrets from Infisical using it. It then formats these secrets using the user provided templates and writes the formatted data to configured file paths. -## Agent configuration file +## Agent configuration file -To set up the authentication method for token renewal and to define secret templates, the Infisical agent requires a YAML configuration file containing properties defined below. +To set up the authentication method for token renewal and to define secret templates, the Infisical agent requires a YAML configuration file containing properties defined below. While specifying an authentication method is mandatory to start the agent, configuring sinks and secret templates are optional. -| Field | Description | -| ------------------------------------------------| ----------------------------- | -| `infisical.address` | The URL of the Infisical service. Default: `"https://app.infisical.com"`. | -| `auth.type` | The type of authentication method used. Available options: `universal-auth`, `kubernetes`, `azure`, `gcp-id-token`, `gcp-iam`, `aws-iam`| -| `auth.config.identity-id` | The file path where the machine identity id is stored

This field is required when using any of the following auth types: `kubernetes`, `azure`, `gcp-id-token`, `gcp-iam`, or `aws-iam`. | -| `auth.config.service-account-token` | Path to the Kubernetes service account token to use (optional)

Default: `/var/run/secrets/kubernetes.io/serviceaccount/token` | -| `auth.config.service-account-key` | Path to your GCP service account key file. This field is required when using `gcp-iam` auth type.

Please note that the file should be in JSON format. | -| `auth.config.client-id` | The file path where the universal-auth client id is stored. | -| `auth.config.client-secret` | The file path where the universal-auth client secret is stored. | -| `auth.config.remove_client_secret_on_read` | This will instruct the agent to remove the client secret from disk. | -| `sinks[].type` | The type of sink in a list of sinks. Each item specifies a sink type. Currently, only `"file"` type is available. | -| `sinks[].config.path` | The file path where the access token should be stored for each sink in the list. | -| `templates[].source-path` | The path to the template file that should be used to render secrets. | -| `templates[].destination-path` | The path where the rendered secrets from the source template will be saved to. | -| `templates[].config.polling-interval` | How frequently to check for secret changes. Default: `5 minutes` (optional) | -| `templates[].config.execute.command` | The command to execute when secret change is detected (optional) | -| `templates[].config.execute.timeout` | How long in seconds to wait for command to execute before timing out (optional) | - +| Field | Description | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `infisical.address` | The URL of the Infisical service. Default: `"https://app.infisical.com"`. | +| `auth.type` | The type of authentication method used. Available options: `universal-auth`, `kubernetes`, `azure`, `gcp-id-token`, `gcp-iam`, `aws-iam` | +| `auth.config.identity-id` | The file path where the machine identity id is stored

This field is required when using any of the following auth types: `kubernetes`, `azure`, `gcp-id-token`, `gcp-iam`, or `aws-iam`. | +| `auth.config.service-account-token` | Path to the Kubernetes service account token to use (optional)

Default: `/var/run/secrets/kubernetes.io/serviceaccount/token` | +| `auth.config.service-account-key` | Path to your GCP service account key file. This field is required when using `gcp-iam` auth type.

Please note that the file should be in JSON format. | +| `auth.config.client-id` | The file path where the universal-auth client id is stored. | +| `auth.config.client-secret` | The file path where the universal-auth client secret is stored. | +| `auth.config.remove_client_secret_on_read` | This will instruct the agent to remove the client secret from disk. | +| `sinks[].type` | The type of sink in a list of sinks. Each item specifies a sink type. Currently, only `"file"` type is available. | +| `sinks[].config.path` | The file path where the access token should be stored for each sink in the list. | +| `templates[].source-path` | The path to the template file that should be used to render secrets. | +| `templates[].template-content` | The format to use for rendering the secrets. | +| `templates[].destination-path` | The path where the rendered secrets from the source template will be saved to. | +| `templates[].config.polling-interval` | How frequently to check for secret changes. Default: `5 minutes` (optional) | +| `templates[].config.execute.command` | The command to execute when secret change is detected (optional) | +| `templates[].config.execute.timeout` | How long in seconds to wait for command to execute before timing out (optional) | ## Authentication @@ -68,19 +72,20 @@ The Infisical agent supports multiple authentication methods. Below are the avai The Universal Auth method is a simple and secure way to authenticate with Infisical. It requires a client ID and a client secret to authenticate with Infisical. - - - - Path to the file containing the universal auth client ID. - - - Path to the file containing the universal auth client secret. - - - Instructs the agent to remove the client secret from disk after reading it. - - - + + + + Path to the file containing the universal auth client ID. + + + Path to the file containing the universal auth client secret. + + + Instructs the agent to remove the client secret from disk after reading + it. + + + @@ -98,21 +103,25 @@ The Infisical agent supports multiple authentication methods. Below are the avai remove_client_secret_on_read: false # Optional field, instructs the agent to remove the client secret from disk after reading it ``` + The Native Kubernetes method is used to authenticate with Infisical when running in a Kubernetes environment. It requires a service account token to authenticate with Infisical. - - - - Path to the file containing the machine identity ID. - - - Path to the Kubernetes service account token to use. Default: `/var/run/secrets/kubernetes.io/serviceaccount/token`. - - - +{" "} + + + + + Path to the file containing the machine identity ID. + + + Path to the Kubernetes service account token to use. Default: + `/var/run/secrets/kubernetes.io/serviceaccount/token`. + + + @@ -129,6 +138,7 @@ The Infisical agent supports multiple authentication methods. Below are the avai service-account-token: "/var/run/secrets/kubernetes.io/serviceaccount/token" # Optional field, custom path to the Kubernetes service account token to use ``` + @@ -186,6 +196,7 @@ The Infisical agent supports multiple authentication methods. Below are the avai ``` + The GCP IAM method is used to authenticate with Infisical with a GCP service account key. @@ -217,6 +228,7 @@ The Infisical agent supports multiple authentication methods. Below are the avai ``` + The AWS IAM method is used to authenticate with Infisical with an AWS IAM role while running in an AWS environment like EC2, Lambda, etc. @@ -244,10 +256,12 @@ The Infisical agent supports multiple authentication methods. Below are the avai ``` + ## Quick start Infisical Agent + To install the Infisical agent, you must first install the [Infisical CLI](../cli/overview) in the desired environment where you'd like the agent to run. This is because the Infisical agent is a sub-command of the Infisical CLI. Once you have the CLI installed, you will need to provision programmatic access for the agent via [Universal Auth](/documentation/platform/identities/universal-auth). To obtain a **Client ID** and a **Client Secret**, follow the step by step guide outlined [here](/documentation/platform/identities/universal-auth). @@ -277,8 +291,8 @@ templates: command: ./reload-app.sh ``` -The secret template below will be used to render the secrets with the key and the value separated by `=` sign. You'll notice that a custom function named `secret` is used to fetch the secrets. -This function takes the following arguments: `secret "" "" ""`. +The secret template below will be used to render the secrets with the key and the value separated by `=` sign. You'll notice that a custom function named `secret` is used to fetch the secrets. +This function takes the following arguments: `secret "" "" ""`. ```text my-dot-ev-secret-template {{- with secret "6553ccb2b7da580d7f6e7260" "dev" "/" }} @@ -290,13 +304,12 @@ This function takes the following arguments: `secret "" " ```bash listSecrets "" "environment-slug" "" @@ -309,11 +322,12 @@ infisical agent --config example-agent-config-file.yaml {{- end }} ``` - **Function name**: listSecrets +**Function name**: listSecrets + +**Description**: This function can be used to render the full list of secrets within a given project, environment and secret path. - **Description**: This function can be used to render the full list of secrets within a given project, environment and secret path. +**Returns**: A single secret object with the following keys `Key, WorkspaceId, Value, Type, ID, and Comment` - **Returns**: A single secret object with the following keys `Key, WorkspaceId, Value, Type, ID, and Comment` @@ -321,18 +335,18 @@ infisical agent --config example-agent-config-file.yaml getSecretByName "" "" "" "" ``` - ```bash example-template-usage - {{ with getSecretByName "d821f21d-aa90-453b-8448-8c78c1160a0e" "dev" "/" "POSTHOG_HOST"}} - {{ if .Value }} - password = "{{ .Value }}" - {{ end }} - {{ end }} - ``` +```bash example-template-usage +{{ with getSecretByName "d821f21d-aa90-453b-8448-8c78c1160a0e" "dev" "/" "POSTHOG_HOST"}} +{{ if .Value }} +password = "{{ .Value }}" +{{ end }} +{{ end }} +``` - **Function name**: getSecretByName +**Function name**: getSecretByName - **Description**: This function can be used to render a single secret by it's name. +**Description**: This function can be used to render a single secret by it's name. - **Returns**: A list of secret objects with the following keys `Key, WorkspaceId, Value, Type, ID, and Comment` +**Returns**: A list of secret objects with the following keys `Key, WorkspaceId, Value, Type, ID, and Comment`