How to hide aws_key_id and aws_secret_key under Rendered Template in AWS MWAA - airflow-2.x

I am using AWS Managed Airflow (MWAA) with Airflow version 2.0.2. To setup External Tables in Snowflake I am using IAM User and I need to pass aws_key_id and aws_secret_key in Create Stage statements. I have templated my Create Stage statements and passing the aws_key_id and aws_secret_key by reading them from AWS Secrets Manager. Here's how my Create Stage statement is
CREATE OR REPLACE STAGE dev_stage.product_analytics.propsect_square_sftp_campaign_data0 URL='s3://rlg-eapedw-qa-curatedzone/nrtllc/curate_zone/campaign' credentials=
(aws_key_id='{{task_instance.xcom_pull(task_ids='read_secrets_manager', key='step_data_1')}}' aws_secret_key='{{task_instance.xcom_pull(task_ids='read_secrets_manager', key='step_data_2')}}') file_format = (TYPE=PARQUET);
But I am finding that after the code runs successfully, the Renderer shows the aws_key_id and aws_secret_key. I am wondering how to avoid this. I tried using mask_secrets from airflow.utils.log.secrets_masker import mask_secret but looks like this is not supported in 2.0.2.
Wondering anyone has solved this problem on AWS.

You can use the Snowflake Storage Integration.
Follow this guide and configure the IAM roles and policies + the integration itself from snowflake.
https://docs.snowflake.com/en/user-guide/data-load-s3-config-storage-integration.html
Eventually you'll end up with a query looking like this:
create stage {stage_name}
storage_integration = {integration_name}
url= {'s3://...'}
file_format=(TYPE = csv SKIP_HEADER = 1);

Related

How to run data bricck notebook with mlflow in azure data factory pipeline?

My colleagues and I are facing an issue when trying to run my databricks notebook in Azure Data Factory and the error is coming from MLFlow.
The command that is failing is the following:
# Take the parent notebook path to use as path for the experiment
context = json.loads(dbutils.notebook.entry_point.getDbutils().notebook().getContext().toJson())
nb_base_path = context['extraContext']['notebook_path'][:-len("00_training_and_validation")]
experiment_path = nb_base_path + 'trainings'
mlflow.set_experiment(experiment_path)
experiment = mlflow.get_experiment_by_name(experiment_path)
experiment_id = experiment.experiment_id
run = mlflow.start_run(experiment_id=experiment_id, run_name=f"run_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}")
And the error that is throwing is:
An exception was thrown from a UDF: 'mlflow.exceptions.RestException: INVALID_PARAMETER_VALUE: No experiment ID was specified. An experiment ID must be specified in Databricks Jobs and when logging to the MLflow server from outside the Databricks workspace. If using the Python fluent API, you can set an active experiment under which to create runs by calling mlflow.set_experiment("/path/to/experiment/in/workspace") at the start of your program.', from , line 32.
The pipeline just runs the notebook from ADF, it does not have any other step and the cluster we are using is type 7.3 ML.
Could you please help us?
Thank you in advance!
I think you need to set artifact URI and specify experiment ID (if in the artifact directory has much experiment ID
Reference: https://www.mlflow.org/docs/latest/tracking.html#how-runs-and-artifacts-are-recorded

How NOT to create a azurerm_mssql_database_extended_auditing_policy

I'm trying to deploy my infra with terraform.
I have a mssql server and database and using azurerm 2.32
While deploying mssql I'm getting following error
Error: issuing create/update request for SQL Server "itan-mssql-server" Blob Auditing Policies(Resource Group "itan-west-europe-resource-group"): sql.ExtendedServerBlobAuditingPoliciesClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="DataSecurityInvalidUserSuppliedParameter" Message="Invalid parameter 'storageEndpoint'. Value should be a blob storage endpoint (e.g. https://MyAccount.blob.core.windows.net)."
I have already tried
defining extended_auditing_policy on database level - failed
defining extended_auditing_policy on server level - failed
defining azurerm_mssql_database_extended_auditing_policy on root level - failed
leaving empty extended_auditing_policy - failed
Global level of definition looks like this (^C^V from terraform documentation with adjustment to my project):
resource "azurerm_mssql_database_extended_auditing_policy" "db-policy" {
database_id = azurerm_mssql_database.itan-mssql-database.id
storage_endpoint = azurerm_storage_account.itan_storage_account.primary_blob_endpoint
storage_account_access_key = azurerm_storage_account.itan_storage_account.primary_access_key
storage_account_access_key_is_secondary = false
retention_in_days = 1
depends_on = [
azurerm_mssql_database.itan-mssql-database,
azurerm_storage_account.itan_storage_account]
}
I'm looking for one of two possible solutions:
total disabling of audits (I don't really needed now)
fixing error and enabling the audit
Thanks!
Jarek
This is caused by Breaking change in the SQL Extended Auditing Settings API. Please check also this issue in terraform provider.
As a workaround you may try call ARM template from terraform. However, I'm not sure if under the hood they use the same or different API.
Workarund that looks to be working for me is like this:
I Followed tip by [ddarwent][1] from git hub:
https://github.com/terraform-providers/terraform-provider-azurerm/issues/8915#issuecomment-711029508
So basically its like this:
terraform apply
Go to terraform.tfstate delete "tainted mssql server"
terraform apply
Go to terraform.tfstate delete "tainted mssql database"
terraform apply
Looks like all my stuff is on and working

Configuration Management in AKS Deployment with Azure Pipelines for Different Environments

I have created a ASP.NET Core WebAPI and deployed in an Dev Environment (Kubernetes) using Azure Pipelines. How can I update the configuration in the pipeline if I need to publish the same API in another environment (eg. SIT). Since I have different settings/configuration for Dev and SIT environments.
Kindly guide me.
You can use release variables to do this. Feel free to reachout if you need any assistance.
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch
https://learn.microsoft.com/en-us/azure/devops/pipelines/release/?view=azure-devops#how-do-i-specify-variables-i-want-to-edit-when-a-release-is-created
The problem occurs when I want to deploy the same API to other
environments like QA/UAT/Prod. Since each environment is having
separate databases
For this issue , there are several ways to achieve this. You can add Replace Tokens extension to the job to replace the database connection string in appsettings.json.
You can define your variable like below:
{
"ConnectionStrings": {
"DefaultConnection": "#{connectstring}#"
}
}
You can refer to this case and lab for details.
Here are some reference for the same issue:
Replacing database connection strings in the Docker image
Set Json Property task to replace the ConnectionStrings

Updating a CloudFormation stack with a Cognito pool claims that we're adding attributes when we're not

Starting on Nov 7, 2018 we started getting the following error when updating our CloudFormation stacks:
Updating user pool schema is not allowed from cloudformation. Use the
AddCustomAttributes API or the AWS Cognito Console to update user pool
schema.
Our CF stacks don't have any changes to the custom attributes of the Cognito pool. They only have changes to the PostConfirmation and CustomMessage triggers, as well the addition of API Gateway responses.
Does anybody know why we might be seeing this? How can we avoid this error message?
We had the same problem with deployment. For now we are deploying it without CustomMessage trigger and setting CustomMessage trigger manually after deployment.
we removed the CustomMessage changes from our template and that seemed to do the trick.
Mostly by luck, I've found an answer that allows me to get around this in an automated manner.
How our scripts used to work
First, let me explain how this used to work. I used to have the following set of cloudFormation scripts:
cognitoSetup.template --> <Serverless Framework> --> <cognitoSetup.template updated with triggers>
So we'd setup the Cognito pool, run the Serverless Framework to add the Cognito Lambda functions, and then update the cognitoSetup.template file with the ARNs for the lambdas exported when the Serverless Framework ran.
The Fix
Now, we include the ARNs for the Lambdas in the cognitoSetup.template. So now cognitoSetup.template looks like this:
"CognitoUserPool": {
"Type": "AWS::Cognito::UserPool"
...
"Properties": {
...
"LambdaConfig": {
"CustomMessage": "arn:aws:lambda:<our aws region>:<our account#>:function:main-<our stage>-onCognitoCustomMessage"
}
}
Note, we're setting this trigger before the lambda even exists. The trigger just needs an ARN, and it doesn't seem to care that it's not there yet. Then we run sls deploy which creates the actual Lambda function and everything works fine.
Now our scripts look like this:
cognitoSetup.template --> <Serverless Framework>
Why does this fix this error? I don't actually know. CloudFormation seems to be fine with this modification but not okay with modifying the same file later in our process. But it works.

EMR Spark Fails to Save Dataframe to S3

I am using the RunJobFlow command to spin up a Spark EMR cluster. This command sets the JobFlowRole to an IAM Role which has the policies AmazonElasticMapReduceforEC2Role and AmazonRedshiftReadOnlyAccess. The first policy contains an action to allow all s3 permissions.
When the EC2 instances spin up, they assume this IAM role, and generate temporary credentials via STS.
The first thing which I do is read a table from my Redshift cluster into a Spark Dataframe using the com.databricks.spark.redshift format and using the same IAM Role to unload the data from redshift as I did for the EMR JobFlowRole.
So far as I understand, this runs an UNLOAD command on Redshift to dump into the S3 bucket I specify. Spark then loads the newly unloaded data into a Dataframe. I use the recommended s3n:// protocol for the tempdir option.
This command works great, and it always successfully loads the data into the Dataframe.
I then run some transformations and attempt to save the dataframe in the csv format to the same S3 bucket Redshift Unloaded into.
However, when I try to do this, it throws the following error
java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, or by setting the fs.s3n.awsAccessKeyId or fs.s3n.awsSecretAccessKey properties (respectively)
Okay. So I don't know why this happens, but I tried to hack around it by setting the recommended hadoop configuration parameters. I then used DefaultAWSCredentialsProviderChain to load the AWSAccessKeyID and AWSSecretKey and set via
spark.sparkContext.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", <CREDENTIALS_ACCESS_KEY>)
spark.sparkContext.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey", <CREDENTIALS_SECRET_ACCESS_KEY>)
When I run it again it throws the following error:
java.io.IOException: com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.services.s3.model.AmazonS3Exception: The AWS Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId;
Okay. So that didn't work. I then removed setting the hadoop configurations and hardcoded an IAM user's credentials in the s3 url via s3n://ACCESS_KEY:SECRET_KEY#BUCKET/KEY
When I ran this it spit out the following error:
java.lang.IllegalArgumentException: Bucket name should be between 3 and 63 characters long
So it tried to create a bucket.. which is definitely not what we want it to do.
I am really stuck on this one and would really appreciate any help here! It works fine when I run it locally, but completely fails on EMR.
The problem was the following:
EC2 Instance Generated Temporary Credentials on EMR Bootstrap Phase
When I queried Redshift, I passed the aws_iam_role to theDatabricks driver. The driver then re-generated temporary credentials for that same IAM role. This invalidated the credentials the EC2 instance generated.
I then tried to upload to S3 using the old credentials (and the credentials which were stored in the instance's metadata)
It failed because it was trying to use out-of-date credentials.
The solution was to remove redshift authorization via aws_iam_role and replace it with the following:
val credentials = EC2MetadataUtils.getIAMSecurityCredentials
...
.option("temporary_aws_access_key_id", credentials.get(IAM_ROLE).accessKeyId)
.option("temporary_aws_secret_access_key", credentials.get(IAM_ROLE).secretAccessKey)
.option("temporary_aws_session_token", credentials.get(IAM_ROLE).token)
On amazon EMR, try usong the prefix s3:// to refer to an object in S3.
It's a long story.