Describe the bug
We use the Vault Agent and templates to render TLS-Certificates from Vault Server.
With the following template file:
{{- /* /opt/vault/templates/client_cert.ctmpl */ -}}
{{- with pkiCert "pki/issue/client-cert" "common_name=node1.example.com" "alt_names= node1.example.com, node1.node.consul,service1.service.consul,localhost" "ip_sans=127.0.0.1,192.168.1.1.1" "format=pem" "ttl=168h" -}}
{{- .Cert -}}
{{- if .Key -}}
{{- .Key | writeToFile "/opt/app/pki/client_cert.key" "app" "app" "0440" -}}
{{- end -}}
{{- end -}}
The cert files are correctly rendered to disk with the correct permissions and owner/group. But when the vault agent checks the cert for renewal it touches the file which is rendered with the writeToFile template function. Causing the modified date to be updated.
Our application uses a FileWatcherService which is watching the certificate files on disk for changes and reloading the app when a change in that files is detected. With the current configuration, see below, this causes a reload every 10 minutes. I’ am not 100% sure but I think this issue was not present before in older vault releases.
We also tried the example template from consul-template docs, and set the template destination to a different file but the behavior is the same:
{{- /* /opt/vault/templates/client_cert.ctmpl */ -}}
{{- with pkiCert "pki/issue/client-cert" "common_name=node1.example.com" "alt_names= node1.example.com, node1.node.consul,service1.service.consul,localhost" "ip_sans=127.0.0.1,192.168.1.1.1" "format=pem" "ttl=168h" -}}
{{ .Cert }}{{ .CA }}{{ .Key }}
{{ .Key | writeToFile "/opt/app/pki/client_cert.key" "app" "app" "0440" }}
{{ .Cert | writeToFile "/opt/app/pki/client_cert.pem" "app" "app" "0440" }}
{{- end -}}
template {
source = "/opt/vault/templates/client_cert.ctmpl"
destination = "/opt/app/pki/cache/client_cert.pem"
perms = 0440
user = "app"
group = "app"
left_delimiter = "{{"
right_delimiter = "}}"
wait {
min = "24h"
max = "72h"
}
}
To Reproduce
Steps to reproduce the behavior:
- Use Vault server and Agent in Version 1.21.4
- Configure vault agent to render template with
pkiCert and writeToFile
- Watch the template destination for changes on disk e.g.
watch -n2 'ls -la /opt/app/pki'
- On every
secret_render_interval (5m by default) the modified timestamp of the files with writeToFile are being updated.
Expected behavior
The files written to disk by the consul-template writeToFile function should not be touched as long there is no need to update them, e. g. in our case the certificate is due to renewal and is being renewed.
Environment:
- Vault Server Version (retrieve with
vault status): 1.21.4
- Vault CLI Version (retrieve with
vault version): Vault v1.21.4 (ffe7023), built 2026-03-04T17:40:05Z
- Server Operating System/Architecture: Red Hat Enterprise Linux 8 and 9 x86_64
Vault server configuration file(s):
pid_file = "/var/run/vault-agent.pid"
vault {
address = https:/vaul.exmple.com:8200
}
auto_auth {
method {
type = "approle"
config = {
role_id_file_path = "/opt/vault/roleid"
secret_id_file_path = "/opt/vault/secretid"
}
}
sink {
type = "file"
config = {
path = "/opt/vault/.token"
mode = 0600
}
}
}
template_config {
exit_on_retry_failure = true
static_secret_render_interval = "10m"
}
template {
source = "/opt/vault/templates/client_cert.ctmpl"
destination = "/opt/app/pki/client_cert.pem"
perms = 0440
user = "app"
group = "app"
left_delimiter = "{{"
right_delimiter = "}}"
wait {
min = "24h"
max = "72h"
}
}
Additional context
I created an auditd rule to see what is happening during rendering of templates:
type=PROCTITLE msg=audit(09.07.2026 12:12:41.480:2196) : proctitle=/usr/bin/vault agent -config=/etc/vault.d/vault.hcl
type=PATH msg=audit(09.07.2026 12:12:41.480:2196) : item=1 name=/opt/app/pki/client_cert.pem inode=5491205 dev=fd:06 mode=file,440 ouid=app ogid=app rdev=00:00 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(09.07.2026 12:12:41.480:2196) : item=0 name=/opt/app/pki/ inode=5491216 dev=fd:06 mode=dir,750 ouid=app ogid=app rdev=00:00 nametype=PARENT cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(09.07.2026 12:12:41.480:2196) : cwd=/
type=SYSCALL msg=audit(09.07.2026 12:12:41.480:2196) : arch=x86_64 syscall=openat success=yes exit=10 a0=AT_FDCWD a1=0xc001b7af00 a2=O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC a3=0x1b6 items=2 ppid=1 pid=1984 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=vault exe=/usr/bin/vault
----
type=PROCTITLE msg=audit(09.07.2026 12:12:41.480:2197) : proctitle=/usr/bin/vault agent -config=/etc/vault.d/vault.hcl
type=PATH msg=audit(09.07.2026 12:12:41.480:2197) : item=0 name=/opt/app/pki/client_cert.pem inode=5491205 dev=fd:06 mode=file,440 ouid=app ogid=app rdev=00:00 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(09.07.2026 12:12:41.480:2197) : cwd=/
type=SYSCALL msg=audit(09.07.2026 12:12:41.480:2197) : arch=x86_64 syscall=fchownat success=yes exit=0 a0=AT_FDCWD a1=0xc001b7af40 a2=0x1777 a3=0x1777 items=1 ppid=1 pid=1984 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=vault exe=/usr/bin/vault
----
type=PROCTITLE msg=audit(09.07.2026 12:12:41.480:2198) : proctitle=/usr/bin/vault agent -config=/etc/vault.d/vault.hcl
type=PATH msg=audit(09.07.2026 12:12:41.480:2198) : item=0 name=/opt/app/pki/client_cert.pem inode=5491205 dev=fd:06 mode=file,440 ouid=app ogid=app rdev=00:00 nametype=NORMAL cap_fp=none cap_fi=none cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(09.07.2026 12:12:41.480:2198) : cwd=/
type=SYSCALL msg=audit(09.07.2026 12:12:41.480:2198) : arch=x86_64 syscall=fchmodat success=yes exit=0 a0=AT_FDCWD a1=0xc001b7af80 a2=0440 a3=0x0 items=1 ppid=1 pid=1984 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=unset comm=vault exe=/usr/bin/vault
Describe the bug
We use the Vault Agent and templates to render TLS-Certificates from Vault Server.
With the following template file:
{{- /* /opt/vault/templates/client_cert.ctmpl */ -}} {{- with pkiCert "pki/issue/client-cert" "common_name=node1.example.com" "alt_names= node1.example.com, node1.node.consul,service1.service.consul,localhost" "ip_sans=127.0.0.1,192.168.1.1.1" "format=pem" "ttl=168h" -}} {{- .Cert -}} {{- if .Key -}} {{- .Key | writeToFile "/opt/app/pki/client_cert.key" "app" "app" "0440" -}} {{- end -}} {{- end -}}The cert files are correctly rendered to disk with the correct permissions and owner/group. But when the vault agent checks the cert for renewal it touches the file which is rendered with the
writeToFiletemplate function. Causing the modified date to be updated.Our application uses a FileWatcherService which is watching the certificate files on disk for changes and reloading the app when a change in that files is detected. With the current configuration, see below, this causes a reload every 10 minutes. I’ am not 100% sure but I think this issue was not present before in older vault releases.
We also tried the example template from consul-template docs, and set the template destination to a different file but the behavior is the same:
{{- /* /opt/vault/templates/client_cert.ctmpl */ -}} {{- with pkiCert "pki/issue/client-cert" "common_name=node1.example.com" "alt_names= node1.example.com, node1.node.consul,service1.service.consul,localhost" "ip_sans=127.0.0.1,192.168.1.1.1" "format=pem" "ttl=168h" -}} {{ .Cert }}{{ .CA }}{{ .Key }} {{ .Key | writeToFile "/opt/app/pki/client_cert.key" "app" "app" "0440" }} {{ .Cert | writeToFile "/opt/app/pki/client_cert.pem" "app" "app" "0440" }} {{- end -}}To Reproduce
Steps to reproduce the behavior:
pkiCertandwriteToFilewatch -n2 'ls -la /opt/app/pki'secret_render_interval(5m by default) the modified timestamp of the files withwriteToFileare being updated.Expected behavior
The files written to disk by the consul-template
writeToFilefunction should not be touched as long there is no need to update them, e. g. in our case the certificate is due to renewal and is being renewed.Environment:
vault status): 1.21.4vault version): Vault v1.21.4 (ffe7023), built 2026-03-04T17:40:05ZVault server configuration file(s):
Additional context
I created an auditd rule to see what is happening during rendering of templates: