I'm writing a KRL module for an API. The API requires an access key, and that needs to be provided by the ruleset that calls my module. My module includes my access key that is used by the in-module test rules.
The ruleset that uses my module provides the access key like this:
use module a421x99 alias SuperModule with access_key = "01234567";
1 - How do I write my module so that the access key doesn't leak into the generated Javascript?
2 - Suppose the calling ruleset doesn't provide an access_key. How do I protect my own access key that I put in the module for testing?
First of all, you ought to be including API keys using a key block in the meta, like this:
key s3 {
"access_key" : "--access_key--"
}
That's better than storing or passing keys in plain strings.
Second, your module needs a configure using line in the meta (I'm assuming you already have one). Passing an empty hash as the default value will prevent your hard-coded key in the module from being used by a ruleset calling the module.
configure using s3keys = {}
Finally, in the global block do something like this:
usekeys = s3keys || keys:s3();
This tells KRL to use either the s3keys that was passed in by the calling ruleset or else the s3 key from the module's own meta block if your module is being used by itself. Even if someone uses your module, they will never get your keys:s3() because of the default value you set in the configure using line.
Once you have usekeys, you can pick() out the pieces you need:
access_key = usekeys.pick("access_key");
Sam's Twilio module is a great place to refer for examples.
Related
When writing terraform modules, one is commonly writing pass through variables/inputs for dependent objects.
How can I write the variable so that the description/type just references the dependent description?
I imagine something like
variable "foo" {
type = dependant.resource.foo.var.type
description = dependant.resource.foo.var.description
default = "module default"
}
Variable descriptions are metadata used by Terraform itself (specifically: by documentation mechanisms like Terraform Registry) and are not data visible to your module code.
Each module's input variables and output values must be entirely self-contained. Mechanisms like the Terraform Registry rely on this so that they are able to generate the documentation for a module only by reference to that module, without any need to fetch and analyze any other modules or other dependencies.
If you do intend to have a variable just "pass through" to a child module or to a resource configuration then you will need to redeclare its type and description in your module.
I would also suggest considering the advice in the documentation section When to write a module; directly passing through a variable to a child object isn't necessarily a wrong thing to do, but it can result from a module not raising the level of abstraction and therefore not passing the test described there.
In such cases, it can be better to use module composition instead of nested modules.
In this case would mean that the caller of your module would themselves call the other module you are currently wrapping. Instead of your module taking that other module's input variables as its own, it would be declared to accept the other module's output values as its input, so that the caller can pass the object representing the first module result into the second module:
module "first" {
# ...
}
module "second" {
# ...
first = module.first
}
Inside this "second" module, the input variable first would be declared as requiring an object type with attributes matching whatever subset of the output values of "first" that the second module depends on.
I'm struggling with Terragrunt (I'm still quite new).
I can describe my problem even using pure Terragrunt repo examples:
Looking here(https://github.com/gruntwork-io/terragrunt-infrastructure-live-example/tree/master/prod/us-east-1/prod/webserver-cluster) we can see terragrunt.hcl that imports a module asg-elb-service taken from particular URL (also terragrunt example)
Now my point is that everything is fine untill module solves all my needs. But using mentioned example let's say that I want to add something on top of this module (e.g listener rule for ALB or anything) - then I would like to rely on module outputs and as we can check "used" module exposes those: outputs (https://github.com/gruntwork-io/terragrunt-infrastructure-modules-example/blob/master/asg-elb-service/outputs.tf)
But how even if I add tf file inside my structure - continuing my example, it would be something like:
I'm just not able to anyhow "interpolate" and get access to those outputs from module :(
terragrunt is a thin wrapper that just provides some extra tools for configuration. terragrunt is used to make management of multiple terraform modules easier, it takes care about remote state and so on. But it does not extend terraform modules by adding some functionality on top of it.
Coming back to your example, common approach is to create a new terraform module, probably on top of the existing one and add missing functionality there. You should consider terraform module as a function that does particular job on a certain level of abstraction. With that said, it's completely valid to create modules that use another modules. Consider following example: you need to provision an infrastructure that can send Slack notifications if AWS CloudWatch alarm is triggered. To simplify it a little bit, let's imagine, that Alarm is already created. The missing part is a Lambda function that will send notification, SNS topic that will trigger Lambda function.
This is something, that can be created using terraform module, but under the hood it will most probably rely on another terraform modules (one that provisions Lambda and another one that provisions SNS topic). Those "internal" modules are on another level of abstraction and you still can reuse them in other cases individually. Pseudo code might look like this:
module "sns_topic" {
source = "git::https://github.com/..."
name = "trigger_lambda_to_send_notification_to_slack"
}
module "labmda_function" {
source = "git::https://github.com/..."
name = "SendMessageToSlack"
...
}
# Invoke Lambda by SNS
resource "aws_sns_topic_subscription" "sns_subscriptions" {
endpoint = module.labmda_function.lambda_endpoint # this is how you reference module output
protocol = "lambda"
topic_arn = module.sns_topic.sns_topic_arn
}
And then, you can simply use this module in terragrunt.
If I create a simple manifest and access the system defined hiera data, it works fine
$testvar=hiera('some var defined at system level')
notify { "Hiera message is $testvar":}
However, if I attempt to access data that is stored within some module ( downloaded from forge ) it does not
include some_module_from_forge
$testvar=hiera('some var defined in the modules hiera')
notify { "Hiera message is $testvar":}
What am I doing wrong ?
Use lookup("module::param") rather than the hiera function when using module data.
Function docs: lookup()
Hiera: Using the lookup function
Here, my question is, we use define function in php to define the
contant globally but how can i achive same thing in nodejs
in php:
define(nameofthecontant, value);
in nodejs how to?
var dataBaseInfo = result.databaseInfo;
// global.DB_HOST = dataBaseInfo['DB_HOST'];
for(var keys in dataBaseInfo) {
global.keys = dataBaseInfo[keys];
}
i have data in result.databaseInfo from database xml file and m trying to create global contant using for loop, its not working
This is how you can define a variable in the global namespace:
global.nameofthecontant = value
This is something that you don't want to do in node.js though. Your question possibly is a duplicate of this question: node.js global variables?
Change your code from this:
global.keys = dataBaseInfo[keys];
to this:
global[keys] = dataBaseInfo[keys];
When you want to access or assign a property and the property name is in a variable, you use the obj[variableName] syntax.
You could also use Object.assign here if you just want to copy a bunch of properties from one object to another:
Object.assign(global, databaseInfo);
As others have said, it is usually frowned upon to use globals in this way in node.js. Instead, you would typically expose these constants in a module and then just require in the module in any other module that wants to access the constants. This makes your code more modular and makes each module more self-contained.
I have a problem with my puppet script.
I would like to get a value set in my resource file. I declare a resource like that
define checkxml(
$account = '',
$pwd = template('abc/abc.erb'),
){
if(empty($pwd)){
fail('pwd empty')
}
}
I call it via :
checkxml{"$agtaccount":
account => $agtaccount,
}
I want to get the value of $pwd. The $pwd will get is value by Template. If i try to show the value in my resource definition it's ok, I get the right value, so the Template works fine.
My problem is to get access this value after calling the ressource. I saw the getparam of stdlib but doesn't work for me.
getparam(Checkxml["$agtaccount"],"pwd")
If i try to get the account parameters instead of pwd it's ok. I think as i doesn't declare the pwd i can't get him back
How can i get him ?
Thanks for your help
Ugh, this looks dangerous. First off I'd recommend to steer clear of that function and the concept it embodies. It faces you with evaluation order dependencies, which can always lead to inconsistent manifest behavior.
As for the retrieval of the value itself - that will likely not work if the default is used. That's because on a catalog building level, there is not yet a value that is being bound to the parameter, if that makes any sense.
The resolution of final parameter values is rather involved, so there are lots of things that can go wrong with a manifest that relies on such introspective functionality.
I recommend to retrieve the desired value in a more central location (that depends on your manifest structure) and use it both when declaring the Checkxml["$agtaccount"] resource as well as its other uses (for which you are currently trying to extract it).