{"id":226,"date":"2021-03-12T20:57:55","date_gmt":"2021-03-12T20:57:55","guid":{"rendered":"https:\/\/andrejacobs.org\/?p=226"},"modified":"2022-04-11T20:24:23","modified_gmt":"2022-04-11T20:24:23","slug":"100-days-of-learning-day-4-using-environment-variables-and-secrets-in-openfaas","status":"publish","type":"post","link":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-4-using-environment-variables-and-secrets-in-openfaas\/","title":{"rendered":"100 Days of Learning: Day 4 \u2013 Using Environment variables and Secrets in OpenFaaS"},"content":{"rendered":"\n
Photo by Zbynek Burival<\/a> on Unsplash<\/a><\/p>\n\n\n\n Here is my Log book<\/a><\/p>\n Today I managed to learn more about OpenFaaS as well as refresh some Swift knowledge.<\/p>\n Learning action point:<\/strong> Is it possible to bundle up functions to be in the same docker container image? At the moment it looks like 1 function = 1 docker image<\/p>\n In Serverless for Everyone Else<\/a>, Alex gives us an example of how environment variables can be supplied to the node.js function via the YAML file.<\/p>\n I am going to see if I can modify my Python function from yesterday to be configurable in the same way.<\/p>\n Added the section Changed the "handler.py" to read the values for the indentation level and whether to sort the JSON keys from the environment variables. The default indentation level is 4 spaces and to not sort the keys.<\/p>\n Deploy<\/p>\n Test<\/p>\n So what is the benefit in using environment variables? It allows you to not hardcode values all over the place in your code. Also I noticed that creating the docker image is quicker when only the yaml has changed.<\/p>\n NOTE:<\/strong> Do not use environment variables to store secret information! See the official OpenFaaS documentation<\/a> for more information. Also there is a really nice example in Serverless for Everyone Else<\/a> that shows how to protect your API using a secret token.<\/p>\n To explore this I am going to deploy a new function that will read a stored secret and return it back to the caller.<\/p>\n Note:<\/strong><\/p>\n Secret name must start and end with an alphanumeric character\nand can only contain lower-case alphanumeric characters, ‘-‘ or ‘.’<\/p>\n Add the names of secrets you want access to the yaml file<\/p>\n I have added a secret with the name "expose-me" and thus our function will have access to it by the file "\/var\/openfaas\/secrets\/expose-me"<\/p>\n Edit the handler.py file<\/p>\n Deploy<\/p>\n Right ok, need to first actually add the secret to be used<\/p>\n Deploy mk2<\/p>\n Test<\/p>\n Ouch! our secret was exposed. Let us see if we can change the secret.<\/p>\n Nuke the exposed secret and hopefully the Python code will blow up.<\/p>\n Learning action point:<\/strong> Will need to read the docs and possibly the code to see how the secrets are stored \/ communicated over to the faasd instance and why remove didn’t remove the stored file.<\/p>\n Objects (instances of a Class) are reference types.<\/p>\n Structs are value types<\/p>\n If you have a number of variables pointing to an object and you mutate the object, then each one of the variables will be pointing to the same mutated object. This could become dangerous if the object are being accessed from different threads and leads to the classic concurrency issue of a race condition.<\/p>\n Structs in Swift allow you to mutate without having the global side effects.<\/p>\n Mutating a struct only changes a single variable and not all variables with the same value.<\/strong><\/p>\n Members of a struct that are declared as var, is still protected based on how the variable is declared.<\/p>\n In order to mutate the member Photo by Zbynek Burival on Unsplash […]<\/p>\nOpenFaaS<\/h2>\n
Supplying configuration values via environment variables<\/h3>\n
environment<\/code> to my "helloworld.yml" file to configure how the JSON will be prettified.<\/p>\n
version: 1.0\nprovider:\n name: openfaas\n gateway: http:\/\/192.168.64.4:8080\nfunctions:\n helloworld:\n lang: python3\n handler: .\/helloworld\n image: dockername\/helloworld:latest\n\n environment:\n indent: 2\n sort_keys: false\n<\/code><\/pre>\n
import json\nimport os\n\ndef handle(req):\n indent = int(os.environ.get('indent', '4'))\n sort_keys = os.environ.get('sort_keys', 'false').lower() in ['true', 'yes', '1']\n data = json.loads(req)\n response = json.dumps(data, indent=indent, sort_keys=sort_keys)\n return response\n<\/code><\/pre>\n
$ faas-cli up -f helloworld.yml\n...\n<Had a few issues because the YAML contained TABS in the wrong places>\n...\nDeployed. 200 OK.\nURL: http:\/\/192.168.64.4:8080\/function\/helloworld.openfaas-fn\n\n<\/code><\/pre>\n
$ curl --data-binary '{"z": 1, "a": 2, "c": 3, "b": 4}' --header "Content-Type: application\/json" http:\/\/192.168.64.4:8080\/function\/helloworld\n{\n "z": 1,\n "a": 2,\n "c": 3,\n "b": 4\n}\n<\/code><\/pre>\n
Supplying secret values to your function<\/h3>\n
# Remember to first mkdir the directory for the function!\n\u256d ~\/Learning\/faasd\/expose [20:05:44]\n\u2570 $ faas-cli new --lang python3 expose\n<\/code><\/pre>\n
version: 1.0\nprovider:\n name: openfaas\n gateway: http:\/\/192.168.64.4:8080\nfunctions:\n expose:\n lang: python3\n handler: .\/expose\n image: dockername\/expose:latest\n\n secrets:\n - expose-me\n<\/code><\/pre>\n
def handle(req):\n with open('\/var\/openfaas\/secrets\/expose-me') as f:\n secret = f.read()\n return secret\n<\/code><\/pre>\n
$ faas-cli up -f expose.yml\n...\nUnexpected status: 400, message: unable to find secret: expose-me\n<\/code><\/pre>\n
$ faas-cli secret create expose-me --from-literal 'All your secrets have been exposed'\n...\nCreating secret: expose-me\nCreated: 200 OK\n\n$ faas-cli secret list\nNAME\nexpose-me\n<\/code><\/pre>\n
$ faas-cli up -f expose.yml\n...\nDeployed. 200 OK.\nURL: http:\/\/192.168.64.4:8080\/function\/expose.openfaas-fn\n<\/code><\/pre>\n
$ curl http:\/\/192.168.64.4:8080\/function\/expose\nAll your secrets have been exposed\n<\/code><\/pre>\n
$ faas-cli secret help\n...\nAvailable Commands:\n create Create a new secret\n list List all secrets\n remove remove a secret\n update Update a secret\n\n$ faas-cli secret update expose-me --from-literal 'Honeypot'\nUpdating secret: expose-me\nUpdated: 200 OK\n\n$ curl http:\/\/192.168.64.4:8080\/function\/expose\nHoneypot\n<\/code><\/pre>\n
$ faas-cli secret remove expose-me\nRemoved.. OK.\n\n$ curl http:\/\/192.168.64.4:8080\/function\/expose\nHoneypot\n# Ouch! ok I wasn't expecting that. My guess is the \/var\/... file still exists\n<\/code><\/pre>\n
\nSwift: Mutating Objects is different than Mutating Structs<\/strong><\/h2>\n
var a = [3, 1, 2]\nlet b = a \/\/ a copy is made (but it will be copy-on-write)\na.sort() \/\/ mutating method\na \/\/ [1, 2, 3]\nb \/\/ [3, 1, 2]\n<\/code><\/pre>\n
struct Event {\n var count: Int \/\/ member count can be mutated\n\n mutating func increment(_ amount: Int) {\n count += amount\n }\n}\n\nlet e = Event()\ne.increment(10) \/\/ This won't compile because the variable e is let\n<\/code><\/pre>\n
count<\/code> even though it has been declared as
var balance<\/code> the variable doing the mutation needs to be declared with
var<\/code><\/p>\n
var e = Event()\ne.increment(10) \/\/ This will now work because the variable is declared as var\n<\/code><\/pre>\n<\/div>\n","protected":false},"excerpt":{"rendered":"