Hello,
I’m working on deploying FluxCD inside K3s and using a sops.template to deploy a sops secret to contain my SSH key. The issue seems to be that when sops-nix imports the key, it doesn’t retain the formatting needed for YAML and then causes it to not to deploy. Does anyone know how to retain the proper YAML formatting when using “config.sops.placeholder”? See my config:
{ config, ... }: {
sops.templates = {
"fluxcd/fluxcd-git-auth.yaml" = {
content = ''
apiVersion: v1
kind: Secret
metadata:
name: forgejo-auth
namespace: flux-system
labels:
toolkit.fluxcd.io/secret-type: git
type: Opaque
stringData:
identity: |
${config.sops.placeholder."fluxcd/ssh-key"}
known_hosts: |
${config.sops.placeholder."forgejo/dev/known-host"}
'';
path = "/var/lib/rancher/k3s/server/manifests/fluxcd-git-auth.yaml";
owner = "root";
group = "root";
mode = "0644";
};
};
}
The yaml file will get a error parsing with invalid document separator due to the “—” in the SSH key.
What — are you referring to? And how did you define said secrets?
The — is like in such of the SSH key such as like:
----END OPENSSH PRIVATE KEY-----
Secrets are defined like:
fluxcd:
ssh-key: |
The start of the SSH key
Then called in configuration.nix like:
secrets."fluxcd/ssh-key" = {};
Then imported such as in the above.
Oh, you’re trying to literally insert the contents of the private key file into YAML? You might be able to patch the go code to permit indentation or whatnot, then expose an option to indent the template somehow, or indent the private key file itself. I wouldn’t recommend either of those options though.
Does flux not support pointing at an external keyfile?
The problem is probably that the multiline string being inserted into your YAML document isn’t indented.
Rather than messing around with producing a particular style of YAML document, I’d recommend using builtins.toJSON on the entire document, as JSON is also valid YAML.
Example:
sops.templates = {
"fluxcd/fluxcd-git-auth.yaml" = {
content = builtins.toJSON {
apiVersion = "v1";
kind = "Secret";
metadata = {
name = "forgejo-auth";
namespace = "flux-system";
labels."toolkit.fluxcd.io/secret-type" = "git";
};
type = "Opaque";
stringData = {
identity = config.sops.placeholder."fluxcd/ssh-key";
known_hosts = config.sops.placeholder."forgejo/dev/known-host";
};
};
# path, mode, etc.
};
};
The resulting file won’t be pretty, but the computer won’t care.
1 Like
Yes, that’s basically what I was getting at.
Anyway, that solution works in this case since private keys don’t use ", but in general the toJSON solution won’t work if there’s any quotes in the input string, since the substitution would happen at runtime without respecting JSON escape rules.
Ugh, I admit I don’t really know anything about sops-nix templating. If it just replaces text without escaping anything, then I think my approach is invalid even for this case — YAML will reinterpret a string with literal line breaks and replace them with spaces. I thought we were just protecting against text being injected in directly from Nix.
sops-nix templates don’t have any mechanism for escaping or transforming replacement strings?
Edit: LOL, clearly not. Typical golang-ware.
Welp, I guess you’re meant to escape your secrets yourself before encrypting them when you use this feature.
2 Likes
Yeah, it is the multiline being inserted isn’t indented. I do have the key piped in the secrets file before encryption, but that doesn’t seem to keep its structure when inserting it in this way.
Well the template engine simply replaces a string with your secret. It does not know that it is a yaml file. So it does not indent new lines in your secret.
I see two possible routes:
- You store the password in a regular file using sops and write a small systemd service that copies it into the yaml and ensure proper indentation yourself
- There is another way to provide the secrets to the application. You could again write a systemd service that executes commands or something.
Alright, I think instead of trying to over engineer something here that I’ll for sure forget how I did 6 months from now, while not preferred, just go in the HTTPS auth. I’ll raise a feature request with the dev to see if it’s possible to add an escaping feature for future use.
Thanks for everyones input!