The documentation on protected variables is pretty obscure. When I make a variable as protected I have to idea how to access it. No matter what I do it is always empty. I have tried base64 encoding it and then base64 encoding it again in the pipeline so I can see what it is and I get an empty string: Cg==. Can someone please explain how to use protected variables?
As #secustor wrote, it is not possible to access protected variables from a branch or tag that is not protected. The variable would be empty if accessed.
From here, two options:
Push to a protected branch or tag (set the branch/tag protected in Settings > Repository)
Mark the variable as not protected (in Settings > CI/CD, under "Variables")
Again, as mentioned by #secustor, there is a good reason behind this logic. You might not want all the developers in your team to be able to access these variables.
Protected variables are only available if there is a job on a protected branch or tag.
The reasoning behind this is to allow setups which prevent right escalations.
E.g. Credentials for the testing environment for Developers on all branches and deployable credentials only on master/release branches. To add code to the second you need Maintainer rights.
In this example, without protected variables, anyone with Developer rights could print the deploy credentials in their branch.
Related
We want to have each of our terraform environments in a separate AWS account in a way that will make it hard for accidental deployments to production to occur. How is this best accomplished?
We are assuming that an account is dedicated to Production, another to PreProduction and potentially other sandbox environments also have unique accounts, perhaps on a per-admin basis. One other assumption is that you have an S3 bucket in each AWS account that is specific to your environment. Also, we expect your AWS account credentials to be managed in ~/.aws/credentials (or with an IAM role perhaps).
Terraform Backend Configuration
There are two states. For the primary state we’re using the concept of Partial Configuration. We can’t pass variables into the backend config through modules or other means because it is read before those are determined.
Terraform Config Setup
This means that we declare the backend with some details missing and then provide them as arguments to terraform init. Once initialized, it is setup until the .terraform directory is removed.
terraform {
backend "s3" {
encrypt = true
key = "name/function/terraform.tfstate"
}
}
Workflow Considerations
We only need to make a change to how we initialize. We use the -backend-config arguments on terraform init. This provides the missing parts of the configuration. I’m providing all of the missing parts through bash aliases in my ~/.bash_profile like this.
alias terrainit='terraform init \
-backend-config "bucket=s3-state-bucket-name" \
-backend-config "dynamodb_table=table-name" \
-backend-config "region=region-name"'
Accidental Misconfiguration Results
If the appropriate required -backend-config arguments are left off, initialization will prompt you for them. If one is provided incorrectly, it will likely cause failure for permissions reasons. Also, the remote state must be configured to match or it will also fail. Multiple mistakes in identifying the appropriate account environment must occur in order to deploy to Production.
Terraform Remote State
The next problem is that the remote states also need to change and can’t be configured through pulling configuration from the backend config; however, the remote states can be set through variables.
Module Setup
To ease switching accounts, we’ve setup a really simple module which takes in a single variable aws-account and returns a bunch of outputs that the remote state can use with appropriate values. We also can include other things that are environment/account specific. The module is a simple main.tf with map variables that have a key of aws-account and a value that is specific to that account. Then we have a bunch of outputs that do a simple lookup of the map variable like this.
variable "aws-region" {
description = "aws region for the environment"
type = "map"
default = {
Production = "us-west-2"
PP = "us-east-2"
}
}
output "aws-region" {
description = “The aws region for the account
value = "${lookup(var.aws-region, var.aws-account, "invalid AWS account specified")}"
}
Terraform Config Setup
First, we must pass the aws-account to the module. This will probably be near the top of main.tf.
module "environment" {
source = "./aws-account"
aws-account = "${var.aws-account}"
}
Then add a variable declaration to your variables.tf.
variable "aws-account" {
description = "The environment name used to identify appropriate AWS account resources used to configure remote states. Pre-Production should be identified by the string PP. Production should be identified by the string Production. Other values may be added for other accounts later."
}
Now that we have account specific variables output from the module, they can be used in the remote state declarations like this.
data "terraform_remote_state" "vpc" {
backend = "s3"
config {
key = "name/vpc/terraform.tfstate"
region = "${module.environment.aws-region}"
bucket = "${module.environment.s3-state-bucket-name}"
}
}
Workflow Consideration
If the workflow changes in no way after setting up like this, the user will be prompted to provide the value for aws-account variable through a prompt like this whenever a plan/apply or the like is performed. The contents of the prompt are the description of the variable in variables.tf.
$ terraform plan
var.aws-account
The environment name used to identify appropriate AWS account
resources used to configure remote states. Pre-Production should be
identified by the string PP. Production should be identified by the
string Production. Other values may be added for other accounts later.
Enter a value:
You can skip the prompt by providing the variable on the command line like this
terraform plan -var="aws-account=PP"
Accidental Misconfiguration Results
If the aws-account variable isn’t specified, it will be requested. If an invalid value is provided that the aws-account module isn’t aware of, it will return errors including the string “invalid AWS account specified” several times because that is the default values of the lookup. If the aws-account is passed correctly, but it doesn’t match up with the values identified in terraform init, it will fail because the aws credentials being used won’t have access to the S3 bucket being identified.
We faced a similar problema and we solved (partially) creating pipelines in Jenkins or any other CI tool.
We had 3 different envs (dev, staging and prod).Same code, different tfvars, different aws accounts.
When terraform code is merged to master can be applied to staging and only when staging is Green, production can be executed.
Nobody runs terraform manually in prod, aws credentials are stored in the CI tool.
This setup can solve an accident like you decribed but also prevents different users applying different local code.
What is the proper way to either delete, disable or at least change the default password of the 'isis-module-security-admin' by means of code or configuration?
The module defines the SeedSecurityModuleService that runs the SeedUsersAndRolesFixtureScript that in turn sets up the account isis-module-security-admin account.
Currently this isn't configurable, but you could raise a PR against SeedSecurityModuleService where the IsisModuleSecurityAdminUser fixture script could use an #Inject ConfigurationService to read the value of the name to use from a config property, eg "isisaddons.module.security.adminUserName"
HTH
Dan
With scope based repository workpsace will all the members be able to check in the code.?
Or only deliver to the stream is possible like public repository work space.
With scope based repository workpsace will all the members be able to check in the code.?
No: only the owner of a repo workspace can check in code, or accept change set from other flow targets.
Or only deliver to the stream is possible like public repository work space.
No: only the owner of a repo workspace can initiate a deliver.
If you want to deliver change set from another repo workspace, you have to accept them in your own repo workspace first (by modifying its flow target in order to temporarily point to that other repo workspace), and then, once accepted, you can deliver them to the stream.
What's the best practice when you have dependencies that you want to be able to configure when creating a PowerShell module in C#?
My specific scenario is that the PowerShell module I am creating via C# code will use a WCF service. Hence, the service's URL must be something that the clients can configure.
Is there a standard approach on this? Or will this be something that must be custom implemented?
A somewhat standard way to do this is to allow a value to be provided as a parameter or default to reading special variable via PSCmdlet's GetVariableValue. This is what the built-in Send-MailMessage cmdlet does. It reads the variable PSEmailServer if no server is provided.
I might not be understanding your question. So I'll posit a few scenarios:
You PS module will always use the same WCF endpoint. In that case you could hardcode the URL in the module
You have a limited number of endpoints to choose from, and there's some algorithm or best practice to associate an endpoint with a particular user, such as the closest geographically, based on the dept or division the user is in, etc.
It's completely up to the end user's preference to choose a URL.
For case #2, I suggest you implement the algorithm/best practice and save the result someplace - as part of the module install.
For case #3, using an environment variable seems reasonable, or a registry setting, or a file in one of the user's profile directories. Probably more important than where you persist the data though, is the interface you give users to change the setting. For example if you used an environment variable, it would be less friendly to tell the user to go to Control Panel, System, Advanced, Environment, User variable, New..., than to provide a simple PS function to change the URL. In fact I'd say providing a cmdlet/function to perform configuration is the closest to a "standard" I can think of.
The user clicks a button, a new form is generated where the user enters his/her password? How can I keep an in-memory copy of the username?
For instance in web forms, I can just use Session ("User"). How can I replicate this with winforms?
Thanks
You could use a static (Shared in VB .NET) object
Example
Public Class SessionInformation
Public Shared Property UserPassword As String
End Class
You can then access this by calling
SessionInformation.UserPassword
Since there seems to be some concerns revolving around whether or not this is a valid implementation I will explain why this is not the best idea.
This creates a single instance of SessionInformation which means that if it is changed anywhere in the program it affects the rest of the program.
Maintaining object persistence can be difficult if you aren't using a database (SQL, Access, a file, etc...) to maintain an out of memory copy of the object that you want to retrieve at a later date. The easiest way to implement this would be to use a SQLCE database that live in your application folder and using standard T-SQL to store the information that you need. However in the case of a password this may be non-ideal due to security issues.
Or the better way for logging in and out user would be to make use of the System.Security.Principal Namespace to create a user for your application.
You don’t need an equivalent to the Session object in web applications. Sessions are only needed because web applications actually have to access variables across process boundaries (= a session in a web application encompasses multiple requests of a user to a web server, and historically each request started a new application!).
In a “normal” application, this isn’t the case – any non-local variable will do. In your particular case, it would make sense for the password form to have a property that contains the username. The user then enters their username and password and the caller of this password form can retrieve the username:
' The caller looks something like this:
Dim pw As New PasswordForm()
pw.ShowDialog() ' Display the dialog, and wait until the user has dismissed it.
Dim theUsername = pw.Username
Inside the PasswordForm, there is something like this:
Public ReadOnly Property Username() As String
Get
' Return the value of the username textbox field.
Return UsernameInput.Text
End Get
End Property
We could get more sophisticated but this will do.
If you need to reuse the username across the application, chances are that you also need to share other information about the user (what are they working on? …). This, in short, is the state of the application and there is usually an object which represents that state. This would be the right place to store the username as well.
If your application only has one other form (the “main dialog”), then just use a private variable inside that form to store the username. No need for a global variable.
Just have a public variable on the forms, never unload the form, and get the data from that form using formname.variablename (define it as public at form level).
This even can be achieved with controls if you set them to public.
BEFORE THE FLAMES: this solves OP problems, whenever if this is optimal, good or anything else, is another problem.