AWS SAM template with YAML boolean environment variable
Recently, I reviewed an AWS SAM template in which one of my team members added
an environment variable ENABLE_FOO (name isn’t important) with the value
true.
Resources:
SomeVeryInterestingFunction:
Type: AWS::Serverless::Function
Properties:
…
Environment:
Variables:
ENABLE_FOO: true
Unquoted string are common in YAML, but this unquoted true isn’t a string,
it’s a boolean, a subtle difference they had not considered.
This wasn’t a case I had encountered or even considered before and it left me quite skeptical, mostly because I didn’t know what to expect in the actual environment variable.
Said team member had tested true and false values, and confirmed they were
passed as string "true" and "false" respectively.
⍝Side note, props to them for testing the off state as well, please test your off state when doing soft rollout !
However, while true and false are the booleans in YAML 1.2, most YAML
parsers will be somewhat compliant with YAML 1.1, which has 22 distinct values
for boolean type.
What would happen in the future when another team member comes along and uses
YES or On instead of true ?
So, that’s what I tested. I passed all those YAML 1.1 boolean values to a simple
python function with returns them in a JSON object from the os.environ dict.
Resources:
YamlBoolEnvVarCheckerFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Handler: lambda_function.lambda_handler
Runtime: python3.11
MemorySize: 128
Environment:
Variables:
BOOL_y: y
BOOL_Y: Y
BOOL_yes: yes
BOOL_Yes: Yes
BOOL_YES: YES
BOOL_n: n
BOOL_N: N
BOOL_no: no
BOOL_No: No
BOOL_NO: NO
BOOL_true: true
BOOL_True: True
BOOL_TRUE: TRUE
BOOL_false: false
BOOL_False: False
BOOL_FALSE: FALSE
BOOL_on: on
BOOL_On: On
BOOL_ON: ON
BOOL_off: off
BOOL_Off: Off
BOOL_OFF: OFF
import json
import os
def lambda_handler(*_):
return json.dumps(
{k: v for k, v in os.environ.items() if k.startswith("BOOL")}
)
Built it and ran it locally:
% sam build && sam local invoke | jq 'fromjson'
And this is the output. Most values give "true" and "false" as expected, the exceptions being the single letter booleans which give themselves as string value.
{
"BOOL_y": "y",
"BOOL_Y": "Y",
"BOOL_yes": "true",
"BOOL_Yes": "true",
"BOOL_YES": "true",
"BOOL_n": "n",
"BOOL_N": "N",
"BOOL_no": "false",
"BOOL_No": "false",
"BOOL_NO": "false",
"BOOL_true": "true",
"BOOL_True": "true",
"BOOL_TRUE": "true",
"BOOL_false": "false",
"BOOL_False": "false",
"BOOL_FALSE": "false",
"BOOL_on": "true",
"BOOL_On": "true",
"BOOL_ON": "true",
"BOOL_off": "false",
"BOOL_Off": "false",
"BOOL_OFF": "false"
}
All in all, this boolean as environment variable seems like a footgun to me, so we improved our internal SAM template standards with a new rule.
Text environment variables in CF & SAM templates must be set as explicit strings with quotation marks.
Finally, having applied the new rule to the original change, the value of ENABLE_FOO became unmistakably clear.
Resources:
SomeVeryInterestingFunction:
Type: AWS::Serverless::Function
Properties:
…
Environment:
Variables:
ENABLE_FOO: "true"
⍝Actually, what we did was change the value to
1which is also unambiguous and aligns with our best practices, but that was a good little exercise nonetheless.