cilium/cilium · error

IPsec key has unsupported format

Error message

IPsec key has unsupported format

What it means

ipsecKeyFromString returns this when the key string from the secret matches none of the registered ipsecParsers regexes. The CLI supports a fixed set of IPsec key string layouts; anything else is rejected before parsing.

Source

Thrown at cilium-cli/encrypt/ipsec_rotate_key.go:86

	return fmt.Sprintf("%d%s %s %s %s %s", k.spi, spiSuffix, k.algo, k.key, k.cipherMode, k.cipherKey)
}

var (
	ipsecKeyRegex       = regexp.MustCompile(`^([[:digit:]]+\+?)[[:space:]](\S+)[[:space:]]([[:alnum:]]+)[[:space:]]([[:digit:]]+)$`)
	cipherIPsecKeyRegex = regexp.MustCompile(`^([[:digit:]]+\+?)[[:space:]](\S+)[[:space:]]([[:alnum:]]+)[[:space:]](\S+)[[:space:]]([[:alnum:]]+)$`)
	ipsecParsers        = map[*regexp.Regexp]func([]string) (ipsecKey, error){
		ipsecKeyRegex:       keyFromSlice,
		cipherIPsecKeyRegex: cipherKeyFromSlice,
	}
)

func ipsecKeyFromString(s string) (ipsecKey, error) {
	for matcher, parser := range ipsecParsers {
		if matcher.MatchString(s) {
			return parser(matcher.FindStringSubmatch(s))
		}
	}
	return ipsecKey{}, fmt.Errorf("IPsec key has unsupported format")
}

func keyFromSlice(parts []string) (ipsecKey, error) {
	if len(parts) != 5 {
		return ipsecKey{}, fmt.Errorf("IPsec key invalid [expected parts: 5, actual parts: %d]", len(parts))
	}
	parts[1] = strings.TrimSuffix(parts[1], "+")
	spi, err := strconv.Atoi(parts[1])
	if err != nil {
		return ipsecKey{}, fmt.Errorf("invalid IPsec key SPI: %s", parts[1])
	}
	size, err := strconv.Atoi(parts[4])
	if err != nil {
		return ipsecKey{}, fmt.Errorf("invalid IPsec key size: %s", parts[4])
	}
	key := ipsecKey{
		spi:  spi,
		algo: parts[2],

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Print the secret value and compare to the expected format '<spi> rfc4106(gcm(aes)) <128/256-bit hex key>'
  2. Strip stray whitespace/newlines and rewrite the key in the canonical format
  3. Use matching CLI/agent versions so parser regexes cover the key format; otherwise recreate via create-key/rotate-key

Example fix

// before: malformed key
"rfc4106(gcm(aes)) abc123"
// after
"3 rfc4106(gcm(aes)) 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
Defensive patterns

Strategy: validation

Validate before calling

const re = /^\d+\s+rfc4106\(gcm\(aes\)\)\s+[0-9a-fA-F]+$/m
if (!re.test(keyStr.trim())) throw new Error('key string not in supported format')

Type guard

function isWellFormedKey(s) { return typeof s === 'string' && /^\d+\s+rfc4106\(gcm\(aes\)\)\s+[0-9a-f]+$/i.test(s.trim()) }

Try / catch

try { await IPsecRotateKey(ctx) } catch (err) { if (/unsupported format/.test(err.message)) { /* rewrite secret keys value canonically or recreate */ } throw err }

Prevention

When it happens

Trigger: IPsecRotateKey reads secret.Data["keys"] and ipsecKeyFromString fails to match any parser — e.g. wrong number of fields, missing rfc4106(gcm(aes)) marker, whitespace/newline corruption, or a future/newer format.

Common situations: Secrets edited by hand with dropped fields; keys written by newer cilium versions with formats the CLI's parser set doesn't know; trailing newlines or CRLF from manual edits.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/f39bf61161aa72e9. Report an issue: GitHub.