diff --git a/EKS/FSxN-as-PVC-for-EKS/terraform/eks-cluster.tf b/EKS/FSxN-as-PVC-for-EKS/terraform/eks-cluster.tf index 02aab13..39bfd3e 100644 --- a/EKS/FSxN-as-PVC-for-EKS/terraform/eks-cluster.tf +++ b/EKS/FSxN-as-PVC-for-EKS/terraform/eks-cluster.tf @@ -81,7 +81,7 @@ resource "aws_iam_policy" "trident_policy" { { "Action": "secretsmanager:GetSecretValue", "Effect": "Allow", - "Resource": aws_secretsmanager_secret_version.fsx_secret_password.arn + "Resource": module.svm_rotate_secret.secret_arn } ], }) diff --git a/EKS/FSxN-as-PVC-for-EKS/terraform/fsx.tf b/EKS/FSxN-as-PVC-for-EKS/terraform/fsx.tf index e1f6e5a..ccefa2a 100644 --- a/EKS/FSxN-as-PVC-for-EKS/terraform/fsx.tf +++ b/EKS/FSxN-as-PVC-for-EKS/terraform/fsx.tf @@ -1,36 +1,15 @@ # -# Generate a random password for FSx -resource "random_string" "fsx_password" { - length = 8 - min_lower = 1 - min_numeric = 1 - min_special = 0 - min_upper = 1 - numeric = true - special = true - override_special = "@$%^&*()_+=" -} - -provider "aws" { - alias = "secrets_provider" - region = var.aws_secrets_region -} -# -# Store the password in AWS Secrets Manager -resource "aws_secretsmanager_secret" "fsx_secret_password" { - provider = aws.secrets_provider - name = "${var.fsx_password_secret_name}-${random_id.id.hex}" -} -resource "aws_secretsmanager_secret_version" "fsx_secret_password" { - provider = aws.secrets_provider - secret_id = aws_secretsmanager_secret.fsx_secret_password.id - secret_string = jsonencode({username = "vsadmin", password = random_string.fsx_password.result}) +# Instantiate an AWS secret for the FSx ONTAP file system. It will set the initial password for the file system. +module "fsxn_rotate_secret" { + source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + fsx_region = var.aws_region + secret_region = var.aws_secrets_region + aws_account_id = var.aws_account_id + secret_name_prefix = var.secret_name_prefix + fsx_id = aws_fsx_ontap_file_system.eksfs.id } # -# Note that this allows traffic from both the private and public subnets. However -# the security groups only allow traffic from the public subnet over port 22 when -# the source has the jump server SG assigned to it. So, basically, it only allows traffic -# from the jump server from the public subnet. +# Create a FSxN file system. resource "aws_fsx_ontap_file_system" "eksfs" { storage_capacity = var.fsxn_storage_capacity subnet_ids = module.vpc.private_subnets @@ -38,16 +17,24 @@ resource "aws_fsx_ontap_file_system" "eksfs" { throughput_capacity = var.fsxn_throughput_capacity preferred_subnet_id = module.vpc.private_subnets[0] security_group_ids = [aws_security_group.fsx_sg.id] - fsx_admin_password = random_string.fsx_password.result - route_table_ids = concat(module.vpc.private_route_table_ids, module.vpc.public_route_table_ids) + route_table_ids = concat(module.vpc.private_route_table_ids, module.vpc.public_route_table_ids) tags = { Name = var.fsx_name } } # +# Instantiate an AWS secret for the storage virtual machine. It will set the initial password for the SVM. +module "svm_rotate_secret" { + source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + fsx_region = var.aws_region + secret_region = var.aws_secrets_region + aws_account_id = var.aws_account_id + secret_name_prefix = var.secret_name_prefix + svm_id = aws_fsx_ontap_storage_virtual_machine.ekssvm.id +} +# # Create a vserver and assign the 'vsadmin' the same password as fsxadmin. resource "aws_fsx_ontap_storage_virtual_machine" "ekssvm" { file_system_id = aws_fsx_ontap_file_system.eksfs.id name = "ekssvm" - svm_admin_password = random_string.fsx_password.result } diff --git a/EKS/FSxN-as-PVC-for-EKS/terraform/outputs.tf b/EKS/FSxN-as-PVC-for-EKS/terraform/outputs.tf index e7f1d4b..aade460 100644 --- a/EKS/FSxN-as-PVC-for-EKS/terraform/outputs.tf +++ b/EKS/FSxN-as-PVC-for-EKS/terraform/outputs.tf @@ -1,14 +1,21 @@ output "region" { - description = "AWS region" value = var.aws_region } output "fsx-password-secret-name" { - value = aws_secretsmanager_secret.fsx_secret_password.name + value = module.fsxn_rotate_secret.secret_name } output "fsx-password-secret-arn" { - value = aws_secretsmanager_secret_version.fsx_secret_password.arn + value = module.fsxn_rotate_secret.secret_arn +} + +output "svm-password-secret-name" { + value = module.svm_rotate_secret.secret_name +} + +output "svm-password-secret-arn" { + value = module.svm_rotate_secret.secret_arn } output "fsx-svm-name" { diff --git a/EKS/FSxN-as-PVC-for-EKS/terraform/variables.tf b/EKS/FSxN-as-PVC-for-EKS/terraform/variables.tf index 51ffeb0..60804dc 100644 --- a/EKS/FSxN-as-PVC-for-EKS/terraform/variables.tf +++ b/EKS/FSxN-as-PVC-for-EKS/terraform/variables.tf @@ -1,26 +1,32 @@ variable "aws_region" { - default = "us-west-2" - description = "aws region where you want the resources deployed." + description = "The AWS region where you want the resources deployed." + type = string } variable "aws_secrets_region" { - default = "us-west-2" - description = "The region where you want the FSxN secret stored within AWS Secrets Manager." + description = "The AWS region where you want the FSxN and SVM secrets stored within AWS Secrets Manager." + type = string +} + +variable "aws_account_id" { + description = "The AWS account ID. Used to create very specific permissions in the IAM role for the EKS cluster." + type = string } variable "fsx_name" { - default = "eksfs" description = "The name you want assigned to the FSxN file system." + default = "eksfs" } -variable "fsx_password_secret_name" { +variable "secret_name_prefix" { + description = "The base name of the secrets (FSxN and SVM) to create within the AWS Secrets Manager. A random string will be appended to the end of the secreate name to ensure no name conflict." default = "fsx-eks-secret" - description = "The base name of the secret to create within the AWS Secrets Manager that will contain the FSxN password. A random string will be appended to the end of the secreate name to ensure no name conflict." } variable "fsxn_storage_capacity" { - default = 1024 description = "The storage capacity, in GiBs, to be allocated to the FSxN clsuter. Must be at least 1024, and less than 196608." + type = number + default = 1024 validation { condition = var.fsxn_storage_capacity >= 1024 && var.fsxn_storage_capacity < 196608 error_message = "The storage capacity must be at least 1024, and less than 196608." @@ -28,8 +34,9 @@ variable "fsxn_storage_capacity" { } variable "fsxn_throughput_capacity" { - default = 128 description = "The throughput capacity to be allocated to the FSxN cluster. Must be 128, 256, 512, 1024, 2048, 4096." + type = string # Set to a string so it can be used in a "contains()" function. + default = 128 validation { condition = contains([128, 256, 512, 1024, 2048, 4096], var.fsxn_throughput_capacity) error_message = "The throughput capacity must be 128, 256, 512, 1024, 2048, or 4096." @@ -38,8 +45,9 @@ variable "fsxn_throughput_capacity" { # # Keep in mind that key pairs are regional, so pick one that is in the region specified above. variable "key_pair_name" { - default = "MUST REPLACE WITH YOUR KEY PAIR NAME" description = "The key pair to associate with the jump server." + default = "MUST REPLACE WITH YOUR KEY PAIR NAME" + type = string validation { condition = var.key_pair_name != "MUST REPLACE WITH YOUR KEY PAIR NAME" error_message = "You must specify a key pair name." @@ -47,8 +55,8 @@ variable "key_pair_name" { } variable "secure_ips" { - default = ["0.0.0.0/0"] description = "List of CIDRs that are allowed to ssh into the jump server." + default = ["0.0.0.0/0"] } ################################################################################ @@ -56,16 +64,19 @@ variable "secure_ips" { ################################################################################ variable "trident_version" { - default = "v24.2.0-eksbuild.1" description = "The version of Astra Trident to 'add-on' to the EKS cluster." + default = "v24.2.0-eksbuild.1" + type = string } variable "kubernetes_version" { - default = 1.29 description = "kubernetes version" + default = 1.29 + type = string } variable "vpc_cidr" { - default = "10.0.0.0/16" description = "default CIDR range of the VPC" + default = "10.0.0.0/16" + type = string } diff --git a/Management-Utilities/fsxn-rotate-secret/README.md b/Management-Utilities/fsxn-rotate-secret/README.md new file mode 100644 index 0000000..b2dd4cb --- /dev/null +++ b/Management-Utilities/fsxn-rotate-secret/README.md @@ -0,0 +1,202 @@ +# Rotate FSxN File System Passwords + +## Introduction +This sample provides a way to rotate a Secrets Manager secret that is used to hold the +password assigned to an FSxN file system or a FSxN Storage Virtual Machine. +It is a Lambda function that is expected to be invoked by the Secrets Manager rotation feature. +The Secrets Manager should invoke the function four times, each time with the `stage` field, in the `event` dictionary passed in, set to one of the following values: + +| Stage | Description | +|------------|-------------| +|createSecret|The function will create a new version of the secret with a "Version Staging ID" of "AWSPENDING". At this point the original secret is still be left as is and will be the default secret returned if no Version Staging ID is provided.| +|setSecret |The function will update the password for the FSxN file system using the new version of the secret.| +|testSecret |Currently no testing is performed. The Lambda function would have to be attached to the same VPC as the FSxN file system to test the password. Since that would potentially make it where you'd have to have a separate function for each FSxN deployment, and potentially have to setup AWS Endpoints for AWS services, a decision was made to not do that. If the Lambda function fails to set the password correctly, you can always use the AWS console, or API, to set it to whatever you need.| +|finishSecret|The function will promote the new password to the "AWSCURRENT" Version Staging ID. This will set the Version Staging ID of the old password to "AWSPREVIOUS".| + +## Set Up +There are a couple way to you can leverage this sample. Either by manually creating a Lambda function with the appropriate permissions and setting up the Secrets Manager rotation service to use it, or by using the Terraform module provided in the `terraform` directory. +### Manual Method + +#### Step 1 - Create a role for the Lambda function +The first step is to create a role for the Lambda function with the following permissions. It should have a trust +relationship with the AWS Lambda service. + +| Permission | Minimal Scope | Notes +|:------------------------|:----------------|:----------------| +| secretsManager:GetSecretValue | \ | \ is the AWS ARN of the secret to rotate. | +| secretsManager:PutSecretValue | \ | \ is the AWS ARN of the secret to rotate. | +| secretsManager:UpdateSecretVersionStage | \ | \ is the AWS ARN of the secret to rotate. | +| secretsManager:DescribeSecret | \ | \ is the AWS ARN of the secret to rotate. | +| secretsmanager:GetRandomPassword | \* | The scope doesn't matter, since this function doesn't have anything to do with any AWS resources. | +| fsx:UpdateFileSystem | \ | \ is the AWS ARN of the FSxN file system to manage. | +| fsx:UpdateStorageVirtualMachine | \ | \ is the AWS ARN of the Storage Virtual Machine to manage. | +| logs:CreateLogGroup | arn:aws:logs:\:\:\* | This allows the Lambda function to create a log group in CloudWatch. This is optional but allows you to get diagnostic information from the Lambda function. | +| logs:CreateLogStream | arn:aws:logs:\:\:log-group:/aws/lambda/\:\* | This allows the Lambda function to create a log stream in CloudWatch. This is optional but allows you to get diagnostic information from the function.| +| logs:PutLogEvents | arn:aws:logs:\:\:log-group:/aws/lambda/\:\* | This allows the Lambda function to write log events to a log stream in CloudWatch. This is optional but allows you to get diagnostic information from the function.| + +#### Step 2 - Create the Lambda Function +##### Step 2.1 +Create a Lambda function with the following parameters: +- Authored from scratch. +- Uses the Python runtime. +- Set the permissions to the role created above. + +##### Step 2.2 - Insert code +After you create the function, you will be able to insert the code included with this +sample into the code box and click "Deploy" to save it. + +##### Step 2.3 - Change permissisons +Change to the `Configuration` tab and select `Permissions` and add a `Resource-based policy` statement that will allow the +secretsmanager AWS service to invoke the Lambda function. Do that do the following: + +- Click on Add Permission +- Then select "AWS Service" +- Put "Allow SecretsManager" in the StatementID (although, it doesn't really matter what you put there) +- The principal should already be set to `secretsmanager.amazonaws.com` +- Set action to `lambda:InvokeFunction` + +#### Step 3 - Enable Secrets Manager Rotation +To enable the rotation of the secret, you will need go to the Secrets Manager page of the AWS console +and click on the secret you want to rotate, then: +##### Step 3.1 - Set the tags +The way Lambda function knows which FSxN file system, or which SVM, to update the password for is +via the tags associated with the secret. The following are the tags that the program looks for: +|Tag Key|Tag Value|Description| +|:------|:--------|:----------| +|region|\|The region the FSxN file system resides in.| +|fsx_id|\|The FSxN file system id.| +|svm_id|\|The Storage Virtual Machine id.| + +Note that the Lambda function can only manage one password, so either set the value for the `fsx_id` or the `svm_id` tag, both not both. + +:warning: **Warning:** If both the `fsx_id` and `svm_id` tags are set, the `svm_id` tag will be used and the fsx_id will be silently ignored. + +##### Step 3.2 - Enable rotation feature +Click on the Rotation tab and then click on the "Edit rotation" button. That should bring up a +pop-up window. Click on the "Automatic rotation" slider to enable the feature and then configure +the rotation schedule the way you want. The last step is to +select the rotation function that you created in the steps above and click on the "Save" button. + +### Terraform Method +The Terraform module provided in the `terraform` directory can be used to create the Secrets Manager +secret setup to use a rotation policy that uses the Lambda function. It will create the following resources: +- A Lambda function used to rotate the secret. +- An IAM role that allows the Lambda function to rotate the secret. +- A Secrets Manager secret with a rotation enabled. + +#### Prerequisites + +1. [Terraform prerequisites](#terraform) +2. [AWS prerequisites](#aws-account-setup) + +##### Terraform + +| Name | Version | +|------|---------| +| terraform | >= 1.6.6 | +| aws provider | >= 5.25 | + +##### AWS Account Setup + +- You must have an AWS Account with necessary permissions to create and manage resources. +- Configure your AWS Credentials on the server running this Terraform module. This can be derived from +several sources, which are applied in the following order: + 1. Parameters in the provider configuration + 2. Environment variables + 3. Shared credentials files + 4. Shared configuration files + 5. Container credentials + 6. Instance profile credentials and Region + + This order matches the precedence used by the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence) and the [AWS SDKs](https://aws.amazon.com/tools/). + +> [!NOTE] +> In this sample, the AWS Credentials were configured through [AWS CLI](https://aws.amazon.com/cli/), which adds them to a shared configuration file (option 4 above). Therefore, this documentation only provides guidance on setting-up the AWS credentials with shared configuration file using AWS CLI. + +#### Usage + +This directory contains a shared Terraform module that can be referenced remotely. **No need to clone the repository in order to use it!** +To reference this module, create a new terraform folder in your local environment, add a main.tf file and modify it according to the instructions below. + +##### AWS provider block + +Add the AWS provider block to your local root `main.tf` file with the required configuration. For more information check [the docs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs) + +Example: +```hcl +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">=5.25" + } + } +} + +provider "aws" { + region = "us-west-2" +} +``` +##### Reference this module + +Add the following module block to your local `main.tf` file. +Make sure to replace all values within `< >` with your own variables. + +```hcl +module "fsxn_rotate_secret" { + source = "github.com/NetApp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + + fsx_region = # The region the FSxN file system resides in. + secret_region = # The region the secret resides in. + aws_account_id = # The AWS account id that the FSxN file system resides in. + fsx_id = + svm_id = + secretNamePrefix = "fsx_admin_secret" + rotationFrequency = "rate(30 days)" +} +``` +Note that the Lambda function can only manage one password, so either set the value for the `fsxId` or the `svmId` tag, but not both. + +:warning: **Warning:** If both the `fsxId` and `svmId` tags are set, the `svmId` tag will be used and the fsxId will be silently ignored. + +At this point, you can run `terraform init` and `terraform apply` to create the secret that will automatically rotate +the password for the FSxN file system or SVM. + +#### Inputs +The following are the inputs for the module: +| Name | Description | Type | Default | Required | +|:-----|:------------|:------:|:---------:|:--------:| +| fsx_region | The region where the FSxN file system resides in. | string | | yes | +| secret_region | The region where the secret will resides in. | string | | yes | +| aws_account_id | The AWS account id that the FSxN file system resides in. Used to create roles with least privilege. | string |\*| no | +| fsx_id | The FSxN file system id. Note that either fsxId or svmId must be provided, but not both | string | | no | +| svm_id | The Storage Virtual Machine id. Note that either fsxId or svmId must be provided, but not both | string | | no | +| secret_name_prefix | The prefix to use for the secret name. | string | fsxn-secret | no | +| rotation_frequency | The frequency to rotate the password in AWS's "rate" or "cron" notation. | string | rate(30 days) | yes | + +#### Outputs +The following are the outputs for the module: +| Name | Description | +|------|-------------| +| secret_arn | The ARN of the secret created. | +| secret_name | The name of the secret created. | +| lambda_arn | The ARN of the Lambda function created. | +| lambda_name | The name of the Lambda function created. | +| role_arn | The ARN of the IAM role created. | +| role_name | The name of the IAM role created. | + +## Author Information + +This repository is maintained by the contributors listed on [GitHub](https://github.com/NetApp/FSx-ONTAP-samples-scripts/graphs/contributors). + +## License + +Licensed under the Apache License, Version 2.0 (the "License"). + +You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an _"AS IS"_ basis, without WARRANTIES or conditions of any kind, either express or implied. + +See the License for the specific language governing permissions and limitations under the License. + +© 2024 NetApp, Inc. All Rights Reserved. diff --git a/Management-Utilities/fsxn-rotate-secret/fsxn_rotate_secret.py b/Management-Utilities/fsxn-rotate-secret/fsxn_rotate_secret.py new file mode 100644 index 0000000..831caa7 --- /dev/null +++ b/Management-Utilities/fsxn-rotate-secret/fsxn_rotate_secret.py @@ -0,0 +1,200 @@ +################################################################################ +# This program is used to rotate a AWS secret manager secret, and update the +# corresponding FSxN file system with the new secret. It depends on the +# secret having the following tags associted with the secret: +# fsxId: The ID of the FSx file system to update. +# region: The region in which the FSx file system is located. +################################################################################ + +import botocore +import boto3 +import logging +import os + +charactersToExcludeInPassword = '/"\'\\' + +################################################################################ +# This function is used to get the value of a tag from a list of tags. +################################################################################ +def getTagValue(tags, key): + for tag in tags: + if tag['Key'] == key: + return tag['Value'] + return None + +################################################################################ +# This function is used to create a new version of a Secret Manager secret +# asscoiated with the supplied token. It will first check to see if a secret +# already exists, and if not, it will create a new secret with version stage +# set to AWSPENDING. +################################################################################ +def create_secret(secretsClient, arn, token): + global logger + # + # Make sure the current secret exists + # + # *NOTE:* The next line is commented out since it breaks if a secret is created + # without a value. + # secretsClient.get_secret_value(SecretId=arn, VersionStage="AWSCURRENT") + # + # Now try to get the secret version, if that fails, put a new secret + try: + secretsClient.get_secret_value(SecretId=arn, VersionId=token, VersionStage="AWSPENDING") + logger.info(f"create_secret: Secret already exist secret for ARN {arn} with VersionId {token}.") + except secretsClient.exceptions.ResourceNotFoundException: + # + # Generate a random password. + passwd = secretsClient.get_random_password(ExcludeCharacters=charactersToExcludeInPassword, PasswordLength=8, IncludeSpace=False) + # + # Put the secret. + secretsClient.put_secret_value(SecretId=arn, ClientRequestToken=token, SecretString=passwd['RandomPassword'], VersionStages=['AWSPENDING']) + logger.info(f"create_secret: Successfully put secret for ARN {arn} with ClientRequestToken {token} and VersionStage = 'AWSPENDING'.") + +################################################################################ +# This functino is used to set the password of an FSxN file system based +# on a secret stored in the Secrets Manager pointed to by the supplied secret +# ARN with VersionId equal to token and VersionStage equal to AWSPENDING. +################################################################################ +def set_secret(secretsClient, arn, token): + global logger + + try: + secretValueResponse = secretsClient.get_secret_value(SecretId=arn, VersionStage="AWSPENDING", VersionId=token) + except botocore.exceptions.ClientError as e: + logger.error(f"Unable to retrieve secret for {arn} in VersionStage = 'AWSPENDING'. Error={e}") + # + # Pass the exception on so the Secret Manager will know that the rotate failed. + raise e + + password = secretValueResponse['SecretString'] + # + # Get the FSx file system ID, SVM ID and region from the secret's tags. + secretMetadata = secretsClient.describe_secret(SecretId=arn) + tags = secretMetadata['Tags'] + fsxId = getTagValue(tags, 'fsx_id') + fsxRegion = getTagValue(tags, 'region') + svmId = getTagValue(tags, 'svm_id') + logging.info(f"fsxId={fsxId}, svmId={svmId}, fsxRegion={fsxRegion}") + + if (fsxId is None and svmId is None) or fsxRegion is None: + message=f"Error, tags 'fsxId' or 'svmId' and the 'region' have to be set on the secret's ({arn}) resource." + logger.error(message) + raise Exception(message) # Signal to the Secrets Manager that the rotation failed. + # + # Update the FSx file system, or SVM, with the new password. + fsxClient = boto3.client(service_name='fsx', region_name=fsxRegion) + if svmId is None or svmId == "": + fsxClient.update_file_system(OntapConfiguration={"FsxAdminPassword": password}, FileSystemId=fsxId) + logger.info(f"Successfully set the FSxN ({fsxId}) password to secret stored in {arn} with a VersionStage = 'AWSPENDING'.") + else: + fsxClient.update_storage_virtual_machine(StorageVirtualMachineId=svmId, SvmAdminPassword=password) + logger.info(f"Successfully set the SVM ({svmId}) password to secret stored in {arn} with a VersionStage = 'AWSPENDING'.") + +################################################################################ +# Usually this function would be used to test that the service has been updated +# to use the new password. However, since the FSx file system is not accessible +# from this Lambda function, unless it is running within the FSxN's VPC, there +# is no way to test that the password has been set correctly. +################################################################################ +def test_secret(secretsClient, arn, token): + global logger + return + +################################################################################ +# This function is used to finalize the secret rotation process. it does this +# by marking the secret version passed in as the AWSCURRENT secret. +################################################################################ +def finish_secret(secretsClient, arn, token): + global logger + # + # First get the current version. + metadata = secretsClient.describe_secret(SecretId=arn) + current_version = None + for version in metadata["VersionIdsToStages"]: + if "AWSCURRENT" in metadata["VersionIdsToStages"][version]: + if version == token: + # + # The new version is already marked as current. + logger.info(f"finishSecret: Version {version} already marked as AWSCURRENT for {arn}") + return + current_version = version + break + # + # Finalize by staging the secret version current + secretsClient.update_secret_version_stage(SecretId=arn, VersionStage="AWSCURRENT", MoveToVersionId=token, RemoveFromVersionId=current_version) + logger.info(f"finishSecret: Successfully set AWSCURRENT stage to version {token} for secret {arn}.") + + +################################################################################ +# This is the main entry point for the Lambda function. It expects the following +# parameters: +# event['SecretId']: The ARN of the secret to rotate. +# event['ClientRequestToken']: The ClientRequestToken associated with the secret version. +# event['Step']: The rotation step (createSecret, setSecret, testSecret, or finishSecret). +# +################################################################################ +def lambda_handler(event, context): + global logger + + arn = event['SecretId'] + token = event['ClientRequestToken'] + step = event['Step'] + + logger = logging.getLogger('fsxn_rotate_secret') + loggingLevel = os.environ.get("loggingLevel") + if loggingLevel is not None: + logger.setLevel(loggingLevel) + else: + logger.setLevel(logging.WARNING) + # + # Set the logging level higher for these noisy modules to mute thier messages. + logging.getLogger("boto3").setLevel(logging.WARNING) + logging.getLogger("botocore").setLevel(logging.WARNING) + + logger.info(f'arn={arn}, token={token}, step={step}.') + # + # Create a client to the secrets manager service. + secretsClient = boto3.client('secretsmanager') + # + # Make sure the version is staged correctly. + metadata = secretsClient.describe_secret(SecretId=arn) + if not metadata['RotationEnabled']: + message = f"Secret {arn} is not enabled for rotation." + logger.error(message) + raise Exception(message) + # + # If rotation is enabled, then a version is created with a version-id + # equal to the token. + versions = metadata['VersionIdsToStages'] + if token not in versions: + message = f"Secret version {token} has no stage for rotation of secret {arn}." + logger.error(message) + raise Exception(message) + # + # Now check that the version hasn't already been promoted to AWSCURRENT and if not + # that a AWSPENDING staging exist. + # *NOTE:* The following is commented out since it breaks if the secret was created + # without a value and this Lambda function is called before a value is set. + #if "AWSCURRENT" in versions[token]: + # logger.info(f"Secret version {token} already set as AWSCURRENT for secret {arn}.") + # return + #elif "AWSPENDING" not in versions[token]: + # message = f"Secret version {token} not set as AWSPENDING for rotation of secret {arn}." + # logger.error(message) + # raise Exception(message) + # + # At this point we are ready to process the request. + if step == "createSecret": + create_secret(secretsClient, arn, token) + + elif step == "setSecret": + set_secret(secretsClient, arn, token) + + elif step == "testSecret": + test_secret(secretsClient, arn, token) + + elif step == "finishSecret": + finish_secret(secretsClient, arn, token) + + else: + raise ValueError(f"Invalid step parameter '{step}'.") diff --git a/Management-Utilities/fsxn-rotate-secret/terraform/fsxn_rotate_secret.py b/Management-Utilities/fsxn-rotate-secret/terraform/fsxn_rotate_secret.py new file mode 120000 index 0000000..6661819 --- /dev/null +++ b/Management-Utilities/fsxn-rotate-secret/terraform/fsxn_rotate_secret.py @@ -0,0 +1 @@ +../fsxn_rotate_secret.py \ No newline at end of file diff --git a/Management-Utilities/fsxn-rotate-secret/terraform/main.tf b/Management-Utilities/fsxn-rotate-secret/terraform/main.tf new file mode 100644 index 0000000..ca71341 --- /dev/null +++ b/Management-Utilities/fsxn-rotate-secret/terraform/main.tf @@ -0,0 +1,145 @@ +# +# To allow support for secrets to be stored in a separate region than the FSxN file system, +# create a provider just for the Secrets Manager. +provider "aws" { + alias = "secrets_provider" + region = var.secret_region +} +# +# Create a random id to ensure no conflicts. +resource "random_id" "id" { + byte_length = 4 +} +# +# Create the assume role policy document for the Lambda function. +data "aws_iam_policy_document" "assume_role" { + statement { + effect = "Allow" + + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + + actions = ["sts:AssumeRole"] + } +} +# +# Create the inline policy document for the Lambda function role. +data "aws_iam_policy_document" "inline_permissions" { + # + # The frist two statements are required for the lambda function to write logs to CloudWatch. + # While not required, are useful for debugging. + statement { + sid = "Sid0" + effect = "Allow" + actions = ["logs:CreateLogGroup"] + resources = ["arn:aws:logs:${var.secret_region}:${var.aws_account_id}:*"] + } + statement { + sid = "Sid1" + effect = "Allow" + actions = [ + "logs:PutLogEvents", + "logs:CreateLogStream" + ] + resources = ["arn:aws:logs:${var.secret_region}:${var.aws_account_id}:log-group:/aws/lambda/${local.lambdaName}:*"] + } + # + # The third statement is required for the lambda function to rotate the secret. + # Both within the Secrets Manager and the FSx file system. + statement { + sid = "Sid2" + effect = "Allow" + actions = [ + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret", + "secretsmanager:PutSecretValue", + "secretsmanager:UpdateSecretVersionStage", + "fsx:UpdateFileSystem", + "fsx:UpdateStorageVirtualMachine" + ] + resources = [ + aws_secretsmanager_secret.secret.arn, + "arn:aws:fsx:${var.fsx_region}:${var.aws_account_id}:storage-virtual-machine/*/${var.svm_id}", + "arn:aws:fsx:${var.fsx_region}:${var.aws_account_id}:file-system/${var.fsx_id}" + ] + } + # + # The fourth statement is required for the lambda function to generate a random password. + statement { + sid = "sid3" + effect = "Allow" + actions = ["secretsmanager:GetRandomPassword"] + resources = ["*"] + } +} +# +# Create a local variable for the Lambda function name, so it can be used in two places without causing a cycle. +locals { + lambdaName = "fsxn_rotate_secret-${random_id.id.hex}" +} +# +# Create the IAM role for the Lambda function. +resource "aws_iam_role" "iam_for_lambda" { + name = "iam_for_lambda-${random_id.id.hex}" + description = "IAM role for the Rotate FSxN Secret Lambda function." + assume_role_policy = data.aws_iam_policy_document.assume_role.json + inline_policy { + name = "required_policy" + policy = data.aws_iam_policy_document.inline_permissions.json + } +} +# +# Create the archive file for the Lambda function. +data "archive_file" "lambda" { + type = "zip" + source_file = "${path.module}/fsxn_rotate_secret.py" + output_path = "fsxn_rotate_secret.zip" +} +# +# Create the Lambda function. +resource "aws_lambda_function" "rotateLambdaFunction" { + provider = aws.secrets_provider + function_name = local.lambdaName + description = var.svm_id != "" ? "Lambda function to rotate the secret for SVM (${var.svm_id})." : "Lambda function to rotate the secret for FSxN File System (${var.fsx_id})." + role = aws_iam_role.iam_for_lambda.arn + runtime = "python3.12" + handler = "fsxn_rotate_secret.lambda_handler" + filename = "fsxn_rotate_secret.zip" + source_code_hash = data.archive_file.lambda.output_base64sha256 +} +# +# Allow Secrets Manager to invoke the Lambda function. +resource "aws_lambda_permission" "allowSecretsManager" { + provider = aws.secrets_provider + statement_id = "AllowExecutionFromSecretsManager" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.rotateLambdaFunction.function_name + principal = "secretsmanager.amazonaws.com" + source_arn = aws_secretsmanager_secret.secret.arn +} +# +# Create the secret with the required tags. +resource "aws_secretsmanager_secret" "secret" { + provider = aws.secrets_provider + name = "${var.secret_name_prefix}-${random_id.id.hex}" + description = var.svm_id != "" ? "Secret for the storage virtual machine (${var.svm_id})." : "Secret for the FSxN file system (${var.fsx_id})." + + tags = { + fsx_id = var.fsx_id + region = var.fsx_region + svm_id = var.svm_id + } +} +# +# Add the rotation Lambda function and rule to the secret. +resource "aws_secretsmanager_secret_rotation" "secretRotation" { + provider = aws.secrets_provider + secret_id = aws_secretsmanager_secret.secret.id + rotation_lambda_arn = aws_lambda_function.rotateLambdaFunction.arn + + rotation_rules { + schedule_expression = var.rotation_frequency + } +} diff --git a/Management-Utilities/fsxn-rotate-secret/terraform/output.tf b/Management-Utilities/fsxn-rotate-secret/terraform/output.tf new file mode 100644 index 0000000..5c670cb --- /dev/null +++ b/Management-Utilities/fsxn-rotate-secret/terraform/output.tf @@ -0,0 +1,29 @@ +output "secret_arn" { + description = "The ARN of the secret that was created." + value = aws_secretsmanager_secret.secret.arn +} + +output "secret_name" { + description = "The name of the secret that was created." + value = aws_secretsmanager_secret.secret.name +} + +output "lambda_arn" { + description = "The ARN of the Lambda function that was created." + value = aws_lambda_function.rotateLambdaFunction.arn +} + +output "lambda_name" { + description = "The name of the Lambda function that was created." + value = aws_lambda_function.rotateLambdaFunction.function_name +} + +output "role_arn" { + description = "The ARN of the role that was created that allows the Lambda function to rotate the secret." + value = aws_iam_role.iam_for_lambda.arn +} + +output "role_name" { + description = "The name of the role that was created that allows the Lambda function to rotate the secret." + value = aws_iam_role.iam_for_lambda.name +} diff --git a/Management-Utilities/fsxn-rotate-secret/terraform/variables.tf b/Management-Utilities/fsxn-rotate-secret/terraform/variables.tf new file mode 100644 index 0000000..00e9ca6 --- /dev/null +++ b/Management-Utilities/fsxn-rotate-secret/terraform/variables.tf @@ -0,0 +1,38 @@ +variable "secret_region" { + description = "The AWS region where the new secret will be created." + type = string +} + +variable "fsx_region" { + description = "The AWS region where the FSxN file system resides." + type = string +} + +variable "aws_account_id" { + description = "The AWS account ID. Use to create very specific permissions." + type = string +} + +variable "secret_name_prefix" { + description = "The prefix to the secret name that will be created that will contain the password. A random nmumber will be appended to the end of the prefix to ensure no conflict will exist with an existing secret." + type = string + default = "fsxn-secret" +} + +variable "fsx_id" { + description = "The FSxN file system ID of the file system that you want to rotate the password on." + type = string + default = "" +} + +variable "svm_id" { + description = "The SVM ID of the SVM that you want to rotate the password on." + type = string + default = "" +} + +variable "rotation_frequency" { + description = "The rotation frequency of the secret. It should express in AWS's rate() or cron() format. The default is once every 30 days." + type = string + default = "rate(30 days)" +} diff --git a/Terraform/deploy-fsx-ontap/module/README.md b/Terraform/deploy-fsx-ontap/module/README.md index be99d16..c921dc5 100644 --- a/Terraform/deploy-fsx-ontap/module/README.md +++ b/Terraform/deploy-fsx-ontap/module/README.md @@ -255,6 +255,7 @@ terraform apply | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| aws_account_id | The AWS account ID. Used to create very specific permissions. | `string` | n/a | yes | | backup_retention_days | The number of days to retain automatic backups. Setting this to 0 disables automatic backups. You can retain automatic backups for a maximum of 90 days. | `number` | `0` | no | | capacity_size_gb | The storage capacity (GiB) of the FSxN file system. Valid values between 1024 and 196608 | `number` | `1024` | no | | cidr_for_sg | cidr block to be used for the created security ingress rules. Set to an empty string if you want to use the source_sg_id as the source. | `string` | `""` | no | @@ -267,7 +268,8 @@ terraform apply | name | The name to assigne to the FSxN file system. | `string` | `"fsx1"` | no | | root_vol_sec_style | Specifies the root volume security style, Valid values are UNIX, NTFS, and MIXED (although MIXED is not recommended). All volumes created under this SVM will inherit the root security style unless the security style is specified on the volume. | `string` | `"UNIX"` | no | | route_table_ids | Specifies the VPC route tables in which your file system's endpoints will be created. You should specify all VPC route tables associated with the subnets in which your clients are located. By default, Amazon FSx selects your VPC's default route table. Note, this variable is only used for MULTI_AZ_1 type deployments. | `list(any)` | `null` | no | -| secret_name | The name of the secure where the FSxN passwood is stored. | `string` | `""` | no | +| secret_name_prefix | The prefix to the secret name that will be created that will contain the FSxN passwords (system, and SVM). | `string` | `"fsxn-secret"` | no | +| secrets_region | The AWS region where the secets for the FSxN file system and SVM will be deployed. | `string` | `""` | no | | security_group_id | If you are not creating the security group, provide the ID of the security group to be used. | `string` | `""` | no | | source_sg_id | The ID of the security group to allow access to the FSxN file system. Set to an empty string if you want to use the cidr_for_sg as the source. | `string` | `""` | no | | subnets | The subnets from where the file system will be accessible from. For MULTI_AZ_1 deployment type, provide both primvary and secondary subnets. For SINGLE_AZ_1 deployment type, only the primary subnet is used. | `map(string)` |
{
"primarysub": "subnet-111111111",
"secondarysub": "subnet-222222222"
}
| no | @@ -281,10 +283,14 @@ terraform apply | Name | Description | |------|-------------| +| fsxn_secret_arn | The ARN of the secret | +| fsxn_secret_name | The Name of the secret | | my_filesystem_id | The ID of the FSxN Filesystem | | my_fsx_ontap_security_group_id | The ID of the FSxN Security Group | | my_svm_id | The ID of the FSxN Storage Virtual Machine | | my_vol_id | The ID of the ONTAP volume in the File System | +| svm_secret_arn | The Name of the secret | +| svm_secret_name | The Name of the secret | ## Author Information diff --git a/Terraform/deploy-fsx-ontap/module/main.tf b/Terraform/deploy-fsx-ontap/module/main.tf index 4c10789..54bb55f 100644 --- a/Terraform/deploy-fsx-ontap/module/main.tf +++ b/Terraform/deploy-fsx-ontap/module/main.tf @@ -26,7 +26,6 @@ resource "aws_fsx_ontap_file_system" "terraform-fsxn" { kms_key_id = var.kms_key_id automatic_backup_retention_days = var.backup_retention_days daily_automatic_backup_start_time = var.daily_backup_start_time - fsx_admin_password = data.aws_secretsmanager_secret_version.fsx_password.secret_string route_table_ids = (var.deployment_type == "MULTI_AZ_1" ? var.route_table_ids : null) tags = merge(var.tags, {Name = var.name }) dynamic "disk_iops_configuration" { @@ -50,6 +49,19 @@ resource "aws_fsx_ontap_file_system" "terraform-fsxn" { } } +data "aws_region" "current" {} + +# +# Instantiate a secret for the FSx ONTAP file system. It will set the initial password for the file system. +module "fsxn_rotate_secret" { + source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + fsx_region = data.aws_region.current.name + secret_region = var.secrets_region != "" ? var.secrets_region : data.aws_region.current.name + aws_account_id = var.aws_account_id + secret_name_prefix = var.secret_name_prefix + fsx_id = aws_fsx_ontap_file_system.terraform-fsxn.id +} + resource "aws_fsx_ontap_storage_virtual_machine" "mysvm" { // REQUIRED PARAMETERS file_system_id = aws_fsx_ontap_file_system.terraform-fsxn.id @@ -58,6 +70,16 @@ resource "aws_fsx_ontap_storage_virtual_machine" "mysvm" { // OPTIONAL PARAMETERS root_volume_security_style = var.root_vol_sec_style } +# +# Instantiate a secret for the FSx ONTAP file system. It will set the initial password for the SVM. +module "svm_rotate_secret" { + source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + fsx_region = data.aws_region.current.name + secret_region = var.secrets_region != "" ? var.secrets_region : data.aws_region.current.name + aws_account_id = var.aws_account_id + secret_name_prefix = var.secret_name_prefix + svm_id = aws_fsx_ontap_storage_virtual_machine.mysvm.id +} resource "aws_fsx_ontap_volume" "myvol" { // REQUIRED PARAMETERS @@ -78,11 +100,3 @@ resource "aws_fsx_ontap_volume" "myvol" { skip_final_backup = var.vol_info["skip_final_backup"] snapshot_policy = var.vol_info["snapshot_policy"] } -# -# The next two data blocks retrieve the secret from Secrets Manager. -data "aws_secretsmanager_secret" "fsx_secret" { - name = var.secret_name -} -data "aws_secretsmanager_secret_version" "fsx_password" { - secret_id = data.aws_secretsmanager_secret.fsx_secret.id -} diff --git a/Terraform/deploy-fsx-ontap/module/output.tf b/Terraform/deploy-fsx-ontap/module/output.tf index 9c25998..231930b 100644 --- a/Terraform/deploy-fsx-ontap/module/output.tf +++ b/Terraform/deploy-fsx-ontap/module/output.tf @@ -17,3 +17,23 @@ output "my_vol_id" { description = "The ID of the ONTAP volume in the File System" value = aws_fsx_ontap_volume.myvol.id } + +output "fsxn_secret_arn" { + description = "The ARN of the secret" + value = module.fsxn_rotate_secret.secret_arn +} + +output "fsxn_secret_name" { + description = "The Name of the secret" + value = module.fsxn_rotate_secret.secret_name +} + +output "svm_secret_arn" { + description = "The Name of the secret" + value = module.svm_rotate_secret.secret_arn +} + +output "svm_secret_name" { + description = "The Name of the secret" + value = module.svm_rotate_secret.secret_name +} diff --git a/Terraform/deploy-fsx-ontap/module/variables.tf b/Terraform/deploy-fsx-ontap/module/variables.tf index 751143f..b9c07eb 100644 --- a/Terraform/deploy-fsx-ontap/module/variables.tf +++ b/Terraform/deploy-fsx-ontap/module/variables.tf @@ -1,3 +1,20 @@ +variable "secrets_region" { + description = "The AWS region where the secets for the FSxN file system and SVM will be deployed." + type = string + default = "" +} + +variable "secret_name_prefix" { + description = "The prefix to the secret name that will be created that will contain the FSxN passwords (system, and SVM)." + type = string + default = "fsxn-secret" +} + +variable "aws_account_id" { + description = "The AWS account ID. Used to create very specific permissions." + type = string +} + variable "tags" { description = "Tags to be applied to the FSxN file system." type = map(any) @@ -119,16 +136,6 @@ variable "disk_iops_configuration" { default = {} } -variable "secret_name" { - description = "The name of the secure where the FSxN passwood is stored." - type = string - default = "" - validation { - condition = var.secret_name != "" - error_message = "You must provide the name of the secret where the FSxN password is stored." - } -} - variable "route_table_ids" { description = "Specifies the VPC route tables in which your file system's endpoints will be created. You should specify all VPC route tables associated with the subnets in which your clients are located. By default, Amazon FSx selects your VPC's default route table. Note, this variable is only used for MULTI_AZ_1 type deployments." type = list(any) diff --git a/Terraform/deploy-fsx-ontap/standalone-module/README.md b/Terraform/deploy-fsx-ontap/standalone-module/README.md index 4b23cae..e3917d2 100644 --- a/Terraform/deploy-fsx-ontap/standalone-module/README.md +++ b/Terraform/deploy-fsx-ontap/standalone-module/README.md @@ -182,21 +182,21 @@ terraform apply | Name | Version | |------|---------| -| aws | 5.25.0 | -| aws.secrets | 5.25.0 | +| aws | >= 5.25.0 | ### Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| aws_secretsmanager_region | The AWS region where the secret is stored. Can be different from the region where the FSxN file system is deployed. | `string` | `"us-east-2"` | no | +| aws_account_id | The AWS account ID. Used to create very specific IAM policies. | `string` | `"*"` | no | | fsx_capacity_size_gb | The storage capacity (GiB) of the FSxN file system. Valid values between 1024 and 196608. | `number` | `1024` | no | | fsx_deploy_type | The filesystem deployment type. Supports MULTI_AZ_1 and SINGLE_AZ_1 | `string` | `"MULTI_AZ_1"` | no | | fsx_name | The deployed filesystem name | `string` | `"terraform-fsxn"` | no | | fsx_region | The AWS region where the FSxN file system to be deployed. | `string` | `"us-west-2"` | no | -| fsx_secret_name | The name of the AWS SecretManager secret that holds the ONTAP administrative password for the fsxadmin user that you can use to administer your file system using the ONTAP CLI and REST API. | `string` | `"fsx_secret"` | no | | fsx_subnets | A list of subnets IDs that the file system will be accessible from. For MULTI_AZ_1 deployment type, provide both subnets. For SINGLE_AZ_1 deployment type, only the primary subnet is used. | `map(any)` |
{
"primarysub": "subnet-22222222",
"secondarysub": "subnet-33333333"
}
| no | | fsx_tput_in_MBps | The throughput capacity (in MBps) for the file system. Valid values are 128, 256, 512, 1024, 2048, and 4096. | `number` | `128` | no | +| secret_name_prefix | The prefix to the secret name that will be created that will contain the FSxN passwords (system, and SVM). | `string` | `"fsxn-secret"` | no | +| secret_region | The AWS region where the secets for the FSxN file system and SVM will be deployed. | `string` | `"us-west-2"` | no | | svm_name | The name of the Storage Virtual Machine | `string` | `"first_svm"` | no | | vol_info | Details for the volume creation | `map(any)` |
{
"cooling_period": 31,
"efficiency": true,
"junction_path": "/vol1",
"size_mg": 1024,
"tier_policy_name": "AUTO",
"vol_name": "vol1"
}
| no | | vpc_id | The ID of the VPC in which the security group will be created. | `string` | `"vpc-11111111"` | no | @@ -206,8 +206,11 @@ terraform apply | Name | Description | |------|-------------| | my_filesystem_id | The ID of the FSxN Filesystem | +| my_filesystem_management_ip | The management IP of the FSxN Filesystem. | | my_fsx_ontap_security_group_id | The ID of the FSxN Security Group | +| my_fsxn_secret_name | The name of the secret containing the ONTAP admin password | | my_svm_id | The ID of the FSxN Storage Virtual Machine | +| my_svm_secret_name | The name of the secret containing the SVM admin password | | my_vol_id | The ID of the ONTAP volume in the File System | ## Author Information diff --git a/Terraform/deploy-fsx-ontap/standalone-module/main.tf b/Terraform/deploy-fsx-ontap/standalone-module/main.tf index 563cc38..d5d8743 100644 --- a/Terraform/deploy-fsx-ontap/standalone-module/main.tf +++ b/Terraform/deploy-fsx-ontap/standalone-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = "5.25.0" + version = ">= 5.25.0" } } } @@ -12,10 +12,14 @@ provider "aws" { region = var.fsx_region } # -# Since the Secrets Manager might be in a different region, create a separate provider for it. -provider "aws" { - alias = "secrets" - region = var.aws_secretsmanager_region +# Instantiate a secret for the FSx ONTAP file system. It will set the initial password for the file system. +module "fsxn_rotate_secret" { + source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + fsx_region = var.fsx_region + secret_region = var.secret_region + aws_account_id = var.aws_account_id + secret_name_prefix = var.secret_name_prefix + fsx_id = aws_fsx_ontap_file_system.terraform-fsxn.id } /* @@ -40,7 +44,6 @@ resource "aws_fsx_ontap_file_system" "terraform-fsxn" { security_group_ids = [aws_security_group.fsx_sg.id] deployment_type = var.fsx_deploy_type throughput_capacity = var.fsx_tput_in_MBps - fsx_admin_password = data.aws_secretsmanager_secret_version.fsx_password.secret_string tags = { Name = var.fsx_name } @@ -57,6 +60,16 @@ resource "aws_fsx_ontap_file_system" "terraform-fsxn" { # throughput_capacity_per_ha_pair = 0 } # +# Instantiate a rotating secret for the storage virtual machine. It will set the initial password for the SVM. +module "svm_rotate_secret" { + source = "github.com/Netapp/FSx-ONTAP-samples-scripts/Management-Utilities/fsxn-rotate-secret/terraform" + fsx_region = var.fsx_region + secret_region = var.secret_region + aws_account_id = var.aws_account_id + secret_name_prefix = var.secret_name_prefix + svm_id = aws_fsx_ontap_storage_virtual_machine.mysvm.id +} +# # Define a storage virtual machine. resource "aws_fsx_ontap_storage_virtual_machine" "mysvm" { // REQUIRED PARAMETERS @@ -93,13 +106,3 @@ resource "aws_fsx_ontap_volume" "myvol" { # snapshot_policy {} # tags = {} } -# -# The next two data blocks retrieve the secret from Secrets Manager. -data "aws_secretsmanager_secret" "fsx_secret" { - provider = aws.secrets - name = var.fsx_secret_name -} -data "aws_secretsmanager_secret_version" "fsx_password" { - provider = aws.secrets - secret_id = data.aws_secretsmanager_secret.fsx_secret.id -} diff --git a/Terraform/deploy-fsx-ontap/standalone-module/output.tf b/Terraform/deploy-fsx-ontap/standalone-module/output.tf index a0f1b20..ca9f711 100644 --- a/Terraform/deploy-fsx-ontap/standalone-module/output.tf +++ b/Terraform/deploy-fsx-ontap/standalone-module/output.tf @@ -8,6 +8,11 @@ output "my_filesystem_id" { value = aws_fsx_ontap_file_system.terraform-fsxn.id } +output "my_filesystem_management_ip" { + description = "The management IP of the FSxN Filesystem." + value = format(join("", aws_fsx_ontap_file_system.terraform-fsxn.endpoints[0].management[0].ip_addresses)) +} + output "my_svm_id" { description = "The ID of the FSxN Storage Virtual Machine" value = aws_fsx_ontap_storage_virtual_machine.mysvm.id @@ -16,4 +21,14 @@ output "my_svm_id" { output "my_vol_id" { description = "The ID of the ONTAP volume in the File System" value = aws_fsx_ontap_volume.myvol.id -} \ No newline at end of file +} + +output "my_fsxn_secret_name" { + description = "The name of the secret containing the ONTAP admin password" + value = module.fsxn_rotate_secret.secret_name +} + +output "my_svm_secret_name" { + description = "The name of the secret containing the SVM admin password" + value = module.svm_rotate_secret.secret_name +} diff --git a/Terraform/deploy-fsx-ontap/standalone-module/variables.tf b/Terraform/deploy-fsx-ontap/standalone-module/variables.tf index 589d887..52ae1dc 100644 --- a/Terraform/deploy-fsx-ontap/standalone-module/variables.tf +++ b/Terraform/deploy-fsx-ontap/standalone-module/variables.tf @@ -1,7 +1,7 @@ -variable "aws_secretsmanager_region" { - description = "The AWS region where the secret is stored. Can be different from the region where the FSxN file system is deployed." - type = string - default = "us-east-2" +variable "aws_account_id" { + description = "The AWS account ID. Used to create very specific IAM policies." + type = string + default = "*" } variable "fsx_capacity_size_gb" { @@ -36,10 +36,10 @@ variable "fsx_region" { default = "us-west-2" } -variable "fsx_secret_name" { - description = "The name of the AWS SecretManager secret that holds the ONTAP administrative password for the fsxadmin user that you can use to administer your file system using the ONTAP CLI and REST API." +variable "secret_region" { + description = "The AWS region where the secets for the FSxN file system and SVM will be deployed." type = string - default = "fsx_secret" + default = "us-west-2" } variable "fsx_subnets" { @@ -61,6 +61,12 @@ variable "fsx_tput_in_MBps" { } } +variable "secret_name_prefix" { + description = "The prefix to the secret name that will be created that will contain the FSxN passwords (system, and SVM)." + type = string + default = "fsxn-secret" +} + variable "svm_name" { description = "The name of the Storage Virtual Machine" type = string