[output_tfvars_file] [-i]
+ csv2tfvars.py --help
+
+ The -i flag enables interactive mode, prompting for any missing required inputs.""",
+ formatter_class=argparse.RawTextHelpFormatter)
+
+ parser.add_argument('-csv', '--csv_file', type=str, required=False, help='Path to the input CSV file. Required unless in interactive mode.')
+ parser.add_argument('-u', '--server_username', type=str, required=False, help='Username for IP cameras. Required unless in interactive mode.')
+ parser.add_argument('-p', '--server_password', type=str, required=False, help='Password for IP cameras. Required unless in interactive mode.')
+ parser.add_argument('-orch', '--orchestrator_name', type=str, required=False, help='Orchestrator client name. Required unless in interactive mode.')
+ parser.add_argument('output_tfvars_file', nargs='?', default=DEFAULT_OUTPUT_TFVARS_FILE, help='Output TFVARS file path. Optional, defaults to BoschIPCameraStores.tfvars.')
+ parser.add_argument('-i', '--interactive', action='store_true', help='Run in interactive mode. Prompts for missing inputs.')
+
+ args = parser.parse_args()
+
+ if interactive:
+ if not args.csv_file:
+ args.csv_file = input("Enter the input CSV file path: ")
+ if not args.server_username:
+ args.server_username = input("Enter the server username: ")
+ if not args.server_password:
+ args.server_password = input("Enter the server password: ")
+ if not args.orchestrator_name:
+ args.orchestrator_name = input("Enter the orchestrator_name: ")
+ if args.output_tfvars_file == DEFAULT_OUTPUT_TFVARS_FILE: # Default value
+ args.output_tfvars_file = input("Enter the output TFVARS file path (default is 'BoschIPCameraStores.tfvars'): ") or DEFAULT_OUTPUT_TFVARS_FILE
+ else:
+ if not args.csv_file or not args.orchestrator_name:
+ parser.print_help()
+ sys.exit(1)
+
+ validate_file_exists(args.csv_file)
+ return args
+
+def main():
+ args = get_args('-i' in sys.argv)
+
+ camera_map = {}
+ with open(args.csv_file, mode='r', encoding='utf-8') as csvfile:
+ reader = csv.DictReader(csvfile)
+ for row in reader:
+ camera_map[row['serial_number']] = {
+ 'ip': row['ip'],
+ }
+
+ with open(args.output_tfvars_file, mode='w', encoding='utf-8') as tfvarsfile:
+ tfvarsfile.write(f'orchestrator_name="{args.orchestrator_name}"\n')
+ tfvarsfile.write(f'server_username="{args.server_username}"\n')
+ tfvarsfile.write(f'server_password="{args.server_password}"\n')
+ tfvarsfile.write('camera_map = {\n')
+ for serial, details in camera_map.items():
+ tfvarsfile.write(f' "{serial}" = "{details["ip"]}"\n')
+ tfvarsfile.write('}\n')
+ print(f"TFVARS file generated: {args.output_tfvars_file}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/examples/terraform/multiple_same_creds/example.csv b/examples/terraform/multiple_same_creds/example.csv
new file mode 100644
index 0000000..7ff3d81
--- /dev/null
+++ b/examples/terraform/multiple_same_creds/example.csv
@@ -0,0 +1,11 @@
+serial_number,ip
+068745431065110091,192.168.0.1:4444
+068745431065110092,192.168.0.2:4444
+068745431065110093,192.168.0.3:4444
+068745431065110094,192.168.0.4:4444
+068745431065110095,192.168.0.5:4444
+068745431065110096,192.168.0.6:4444
+068745431065110097,192.168.0.7:4444
+068745431065110098,192.168.0.8:4444
+068745431065110099,192.168.0.8:4444
+068745431065110100,192.168.0.9:4444
\ No newline at end of file
diff --git a/examples/terraform/multiple_same_creds/example.tfvars b/examples/terraform/multiple_same_creds/example.tfvars
new file mode 100644
index 0000000..ef80fd7
--- /dev/null
+++ b/examples/terraform/multiple_same_creds/example.tfvars
@@ -0,0 +1,30 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+# UNCOMMENT AND FILL IN THE FOLLOWING VARIABLES
+
+# orchestrator_name="my-uo-client-machine-name"
+# server_username="camera_username"
+# server_password="camera_password"
+# camera_map = {
+# "068745431065110091" = "192.168.0.1:4444",
+# "068745431065110092" = "192.168.0.2:4444",
+# "068745431065110093" = "192.168.0.3:4444",
+# "068745431065110094" = "192.168.0.4:4444",
+# "068745431065110095" = "192.168.0.5:4444",
+# "068745431065110096" = "192.168.0.6:4444",
+# "068745431065110097" = "192.168.0.7:4444",
+# "068745431065110098" = "192.168.0.8:4444",
+# "068745431065110099" = "192.168.0.8:4444",
+# }
\ No newline at end of file
diff --git a/examples/terraform/multiple_same_creds/main.tf b/examples/terraform/multiple_same_creds/main.tf
new file mode 100644
index 0000000..3ffc2c8
--- /dev/null
+++ b/examples/terraform/multiple_same_creds/main.tf
@@ -0,0 +1,25 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+resource "keyfactor_certificate_store" "bosch_camera_store" {
+ for_each = var.camera_map
+ client_machine = each.value //this is camera IP
+ store_path = each.key //this is camera serial number
+ agent_identifier = data.keyfactor_agent.universal_orchestrator.agent_identifier
+ store_type = "BIPCamera" # Must exist in KeyFactor Command
+ server_username = var.server_username
+ server_password = var.server_password
+ server_use_ssl = var.server_use_ssl
+ inventory_schedule = var.inventory_schedule
+}
diff --git a/examples/terraform/multiple_same_creds/providers.tf b/examples/terraform/multiple_same_creds/providers.tf
new file mode 100644
index 0000000..28d243c
--- /dev/null
+++ b/examples/terraform/multiple_same_creds/providers.tf
@@ -0,0 +1,26 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+terraform {
+ required_version = ">= 1.5"
+ required_providers {
+ keyfactor = {
+ source = "keyfactor-pub/keyfactor"
+ version = ">=2.1.5"
+ }
+ }
+}
+provider "keyfactor" {
+
+}
diff --git a/examples/terraform/multiple_same_creds/variables.tf b/examples/terraform/multiple_same_creds/variables.tf
new file mode 100644
index 0000000..46b5ac6
--- /dev/null
+++ b/examples/terraform/multiple_same_creds/variables.tf
@@ -0,0 +1,45 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+variable "orchestrator_name" {
+ type = string
+ description = "The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command"
+}
+
+variable "camera_map" {
+ type = map(string)
+ description = "A map containing the serial number to IP address of the cameras to be enrolled"
+}
+
+variable "server_username" {
+ type = string
+ sensitive = true
+ description = "The username to authenticate to the Bosch camera"
+}
+variable "server_password" {
+ type = string
+ sensitive = true
+ description = "The password to authenticate to the Bosch camera"
+}
+variable "inventory_schedule" {
+ type = string
+ description = "How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update."
+ default = "12h"
+}
+
+variable "server_use_ssl" {
+ default = true
+ type = bool
+ description = "Whether to use SSL when connecting to the Bosch camera"
+}
\ No newline at end of file
diff --git a/examples/terraform/multiple_unique_creds/MODULE.MD b/examples/terraform/multiple_unique_creds/MODULE.MD
new file mode 100644
index 0000000..01b65cb
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/MODULE.MD
@@ -0,0 +1,38 @@
+## Requirements
+
+| Name | Version |
+|---------------------------------------------------------------------------|---------|
+| [terraform](#requirement\_terraform) | >= 1.5 |
+| [keyfactor](#requirement\_keyfactor) | >=2.1.5 |
+
+## Providers
+
+| Name | Version |
+|---------------------------------------------------------------------|---------|
+| [keyfactor](#provider\_keyfactor) | 2.1.11 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
+| [keyfactor_certificate_store.bosch_camera_store](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/resources/certificate_store) | resource |
+| [keyfactor_agent.universal_orchestrator](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/data-sources/agent) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|---------|:--------:|
+| [camera\_map](#input\_camera\_map) | A map containing the serial number to IP address, username and password of the cameras to be enrolled | map(object({
ip = string
username = string
password = string
})) | n/a | yes |
+| [inventory\_schedule](#input\_inventory\_schedule) | How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update. | `string` | `"12h"` | no |
+| [orchestrator\_name](#input\_orchestrator\_name) | The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command | `string` | n/a | yes |
+| [server\_password](#input\_server\_password) | The password to authenticate to the Bosch camera | `string` | n/a | yes |
+| [server\_use\_ssl](#input\_server\_use\_ssl) | Whether to use SSL when connecting to the Bosch camera | `bool` | `true` | no |
+| [server\_username](#input\_server\_username) | The username to authenticate to the Bosch camera | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
diff --git a/examples/terraform/multiple_unique_creds/Makefile b/examples/terraform/multiple_unique_creds/Makefile
new file mode 100644
index 0000000..1db769c
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/Makefile
@@ -0,0 +1,40 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+.DEFAULT_GOAL := help
+
+##@ Utility
+help: ## Display this help
+ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+deps: ## Install deps for macos
+ @brew install pre-commit tflint terraform terraform-docs
+
+docs: ## Run terraform-docs to update module docs.
+ @terraform-docs markdown . > MODULE.MD
+ @terraform-docs markdown table --output-file README.md --output-mode inject .
+
+lint: ## Run tflint
+ @tflint
+
+validate: ## Run terraform validate
+ @terraform init --upgrade
+ @terraform validate
+
+precommit/add: ## Install pre-commit hook
+ @pre-commit install
+
+precommit/remove: ## Uninstall pre-commit hook
+ @pre-commit uninstall
+
diff --git a/examples/terraform/multiple_unique_creds/README.md b/examples/terraform/multiple_unique_creds/README.md
new file mode 100644
index 0000000..e99aaf5
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/README.md
@@ -0,0 +1,117 @@
+# Multiple BoschIPCamera Store Creation using Unique Credentials Example
+
+This is an example of how to create multiple camera stores in Keyfactor Command using the Keyfactor Terraform provider.
+
+## Pre-requisites
+
+- Terraform is installed on the machine running the Terraform code
+- The Keyfactor Terraform provider is installed and configured to communicate to Keyfactor Command. Review
+ the [Keyfactor provider documentation](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs)
+ for more information.
+- The `BIPCamera` store type is already created in Keyfactor Command. See
+ the [Extension specific documentation](https://github.com/Keyfactor/bosch-ipcamera-orchestrator?tab=readme-ov-file#store-type-configuration)
+ for more information.
+- An orchestrator with the BoschIPCamera extension is registered and approved in Keyfactor Command.
+
+## Usage
+
+Modify the `example.tfvars` file to include the necessary information for your environment. Alternatively Terraform will
+prompt for each input if no value is provided.
+
+```bash
+terraform init
+terraform plan
+terraform apply
+```
+
+### Generate tfvars file from CSV
+
+Alternatively, you can generate the `.tfvars` file from a CSV file using the template `example.csv` and running the
+python script `csv2tfvars.py`. This script will generate a `.tfvars` based on the inputs of the CSV file.
+
+#### Usage
+
+```text
+python csv2tfvars.py -h
+usage: csv2tfvars.py [-h] -csv CSV_FILE -orch ORCHESTRATOR_NAME [-i] [output_tfvars_file]
+
+ Convert CSV to TFVARS. This script parses a given CSV file containing camera information and generates a Terraform variables file (.tfvars) with the data structured for Terraform usage.
+
+ Usage:
+ csv2tfvars.py -csv -orch [output_tfvars_file] [-i]
+ csv2tfvars.py --help
+
+ The -i flag enables interactive mode, prompting for any missing required inputs.
+
+positional arguments:
+ output_tfvars_file Output TFVARS file path. Optional, defaults to BoschIPCameraStores.tfvars.
+
+optional arguments:
+ -h, --help show this help message and exit
+ -csv CSV_FILE, --csv_file CSV_FILE
+ Path to the input CSV file. Required unless in interactive mode.
+ -orch ORCHESTRATOR_NAME, --orchestrator_name ORCHESTRATOR_NAME
+ Orchestrator name. Required unless in interactive mode.
+ -i, --interactive Run in interactive mode. Prompts for missing inputs.
+```
+
+#### Interactive Example
+
+```bash
+python csv2tfvars.py -i
+```
+
+```text
+Enter the input CSV file path: example.csv
+Enter the orchestrator_name: my-uo-client-name
+Enter the output TFVARS file path (default is 'BoschIPCameraStores.tfvars'):
+TFVARS file generated: BoschIPCameraStores.tfvars
+```
+
+#### Non-Interactive Example
+
+```bash
+python csv2tfvars.py -csv example.csv -orch my-uo-client-name
+```
+
+
+
+## Requirements
+
+| Name | Version |
+|---------------------------------------------------------------------------|---------|
+| [terraform](#requirement\_terraform) | >= 1.5 |
+| [keyfactor](#requirement\_keyfactor) | >=2.1.5 |
+
+## Providers
+
+| Name | Version |
+|---------------------------------------------------------------------|---------|
+| [keyfactor](#provider\_keyfactor) | 2.1.11 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
+| [keyfactor_certificate_store.bosch_camera_store](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/resources/certificate_store) | resource |
+| [keyfactor_agent.universal_orchestrator](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/data-sources/agent) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|--------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|---------|:--------:|
+| [camera\_map](#input\_camera\_map) | A map containing the serial number to IP address, username and password of the cameras to be enrolled | map(object({
ip = string
username = string
password = string
})) | n/a | yes |
+| [inventory\_schedule](#input\_inventory\_schedule) | How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update. | `string` | `"12h"` | no |
+| [orchestrator\_name](#input\_orchestrator\_name) | The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command | `string` | n/a | yes |
+| [server\_password](#input\_server\_password) | The password to authenticate to the Bosch camera | `string` | n/a | yes |
+| [server\_use\_ssl](#input\_server\_use\_ssl) | Whether to use SSL when connecting to the Bosch camera | `bool` | `true` | no |
+| [server\_username](#input\_server\_username) | The username to authenticate to the Bosch camera | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
+
\ No newline at end of file
diff --git a/examples/terraform/multiple_unique_creds/agents.tf b/examples/terraform/multiple_unique_creds/agents.tf
new file mode 100644
index 0000000..6406bae
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/agents.tf
@@ -0,0 +1,17 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+data "keyfactor_agent" "universal_orchestrator" {
+ agent_identifier = var.orchestrator_name
+}
\ No newline at end of file
diff --git a/examples/terraform/multiple_unique_creds/csv2tfvars.py b/examples/terraform/multiple_unique_creds/csv2tfvars.py
new file mode 100644
index 0000000..fdbeba6
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/csv2tfvars.py
@@ -0,0 +1,72 @@
+import argparse
+import csv
+import os
+import sys
+
+DEFAULT_OUTPUT_TFVARS_FILE = 'BoschIPCameraStores.tfvars'
+
+def validate_file_exists(file_path):
+ if not os.path.exists(file_path):
+ print(f"Error: The file '{file_path}' does not exist.")
+ sys.exit(1)
+
+def get_args(interactive):
+ parser = argparse.ArgumentParser(description="""
+ Convert CSV to TFVARS. This script parses a given CSV file containing camera information and generates a Terraform variables file (.tfvars) with the data structured for Terraform usage.
+
+ Usage:
+ csv2tfvars.py -csv -orch [output_tfvars_file] [-i]
+ csv2tfvars.py --help
+
+ The -i flag enables interactive mode, prompting for any missing required inputs.""",
+ formatter_class=argparse.RawTextHelpFormatter)
+
+ parser.add_argument('-csv', '--csv_file', type=str, required=False, help='Path to the input CSV file. Required unless in interactive mode.')
+ parser.add_argument('-orch', '--orchestrator_name', type=str, required=False, help='Orchestrator name. Required unless in interactive mode.')
+ parser.add_argument('output_tfvars_file', nargs='?', default=DEFAULT_OUTPUT_TFVARS_FILE, help='Output TFVARS file path. Optional, defaults to BoschIPCameraStores.tfvars.')
+ parser.add_argument('-i', '--interactive', action='store_true', help='Run in interactive mode. Prompts for missing inputs.')
+
+ args = parser.parse_args()
+
+ if interactive:
+ if not args.csv_file:
+ args.csv_file = input("Enter the input CSV file path: ")
+ if not args.orchestrator_name:
+ args.orchestrator_name = input("Enter the orchestrator_name: ")
+ if args.output_tfvars_file == DEFAULT_OUTPUT_TFVARS_FILE: # Default value
+ args.output_tfvars_file = input("Enter the output TFVARS file path (default is 'BoschIPCameraStores.tfvars'): ") or DEFAULT_OUTPUT_TFVARS_FILE
+ else:
+ if not args.csv_file or not args.orchestrator_name:
+ parser.print_help()
+ sys.exit(1)
+
+ validate_file_exists(args.csv_file)
+ return args
+
+def main():
+ args = get_args('-i' in sys.argv)
+
+ camera_map = {}
+ with open(args.csv_file, mode='r', encoding='utf-8') as csvfile:
+ reader = csv.DictReader(csvfile)
+ for row in reader:
+ camera_map[row['serial_number']] = {
+ 'ip': row['ip'],
+ 'username': row['username'],
+ 'password': row['password']
+ }
+
+ with open(args.output_tfvars_file, mode='w', encoding='utf-8') as tfvarsfile:
+ tfvarsfile.write(f'orchestrator_name="{args.orchestrator_name}"\n')
+ tfvarsfile.write('camera_map = {\n')
+ for serial, details in camera_map.items():
+ tfvarsfile.write(f' "{serial}" = {{\n')
+ tfvarsfile.write(f' ip = "{details["ip"]}"\n')
+ tfvarsfile.write(f' username = "{details["username"]}"\n')
+ tfvarsfile.write(f' password = "{details["password"]}"\n')
+ tfvarsfile.write(' }\n')
+ tfvarsfile.write('}\n')
+ print(f"TFVARS file generated: {args.output_tfvars_file}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/examples/terraform/multiple_unique_creds/example.csv b/examples/terraform/multiple_unique_creds/example.csv
new file mode 100644
index 0000000..ff74c3f
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/example.csv
@@ -0,0 +1,11 @@
+serial_number,ip,username,password
+068745431065110091,192.168.0.1:4444,camera1_admin,camera1_password
+068745431065110092,192.168.0.2:4444,camera2_admin,camera2_password
+068745431065110093,192.168.0.3:4444,camera3_admin,camera3_password
+068745431065110094,192.168.0.4:4444,camera4_admin,camera4_password
+068745431065110095,192.168.0.5:4444,camera5_admin,camera5_password
+068745431065110096,192.168.0.6:4444,camera6_admin,camera6_password
+068745431065110097,192.168.0.7:4444,camera7_admin,camera7_password
+068745431065110098,192.168.0.8:4444,camera8_admin,camera8_password
+068745431065110099,192.168.0.8:4444,camera9_admin,camera9_password
+068745431065110100,192.168.0.9:4444,camera10_admin,camera10_password
\ No newline at end of file
diff --git a/examples/terraform/multiple_unique_creds/example.tfvars b/examples/terraform/multiple_unique_creds/example.tfvars
new file mode 100644
index 0000000..642f5ce
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/example.tfvars
@@ -0,0 +1,66 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+# UNCOMMENT AND FILL IN THE FOLLOWING VARIABLES
+
+# orchestrator_name="my-uo-client-machine-name"
+# server_username="camera_username"
+# server_password="camera_password"
+# camera_map = {
+# "068745431065110091" = {
+# ip = "192.168.0.1:4444",
+# username = "camera1_admin",
+# password = "camera1_password"
+# },
+# "068745431065110092" = {
+# ip = "192.168.0.2:4444",
+# username = "camera2_admin",
+# password = "camera2_password"
+# },
+# "068745431065110093" = {
+# ip = "192.168.0.3:4444",
+# username = "camera3_admin",
+# password = "camera3_password"
+# },
+# "068745431065110094" = {
+# ip = "192.168.0.4:4444",
+# username = "camera4_admin",
+# password = "camera4_password"
+# },
+# "068745431065110095" = {
+# ip = "192.168.0.5:4444",
+# username = "camera5_admin",
+# password = "camera5_password"
+# },
+# "068745431065110096" = {
+# ip = "192.168.0.6:4444",
+# username = "camera6_admin",
+# password = "camera6_password"
+# },
+# "068745431065110097" = {
+# ip = "192.168.0.7:4444",
+# username = "camera7_admin",
+# password = "camera7_password"
+# },
+# "068745431065110098" = {
+# ip = "192.168.0.8:4444",
+# username = "camera8_admin",
+# password = "camera8_password"
+# },
+# "068745431065110099" = {
+# ip = "192.168.0.8:4444",
+# username = "camera9_admin",
+# password = "camera9_password"
+# }
+# }
\ No newline at end of file
diff --git a/examples/terraform/multiple_unique_creds/main.tf b/examples/terraform/multiple_unique_creds/main.tf
new file mode 100644
index 0000000..0db5d28
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/main.tf
@@ -0,0 +1,25 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+resource "keyfactor_certificate_store" "bosch_camera_store" {
+ for_each = var.camera_map
+ client_machine = each.value.ip //this is camera IP
+ store_path = each.key //this is camera serial number
+ agent_identifier = data.keyfactor_agent.universal_orchestrator.agent_identifier
+ store_type = "BIPCamera" # Must exist in KeyFactor Command
+ server_username = each.value.username
+ server_password = each.value.password
+ server_use_ssl = var.server_use_ssl
+ inventory_schedule = var.inventory_schedule
+}
diff --git a/examples/terraform/multiple_unique_creds/providers.tf b/examples/terraform/multiple_unique_creds/providers.tf
new file mode 100644
index 0000000..28d243c
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/providers.tf
@@ -0,0 +1,26 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+terraform {
+ required_version = ">= 1.5"
+ required_providers {
+ keyfactor = {
+ source = "keyfactor-pub/keyfactor"
+ version = ">=2.1.5"
+ }
+ }
+}
+provider "keyfactor" {
+
+}
diff --git a/examples/terraform/multiple_unique_creds/variables.tf b/examples/terraform/multiple_unique_creds/variables.tf
new file mode 100644
index 0000000..c7cf1e8
--- /dev/null
+++ b/examples/terraform/multiple_unique_creds/variables.tf
@@ -0,0 +1,49 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+variable "orchestrator_name" {
+ type = string
+ description = "The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command"
+}
+
+variable "camera_map" {
+ type = map(object({
+ ip = string
+ username = string
+ password = string
+ }))
+ description = "A map containing the serial number to IP address, username and password of the cameras to be enrolled"
+}
+
+variable "server_username" {
+ type = string
+ sensitive = true
+ description = "The username to authenticate to the Bosch camera"
+}
+variable "server_password" {
+ type = string
+ sensitive = true
+ description = "The password to authenticate to the Bosch camera"
+}
+variable "inventory_schedule" {
+ type = string
+ description = "How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update."
+ default = "12h"
+}
+
+variable "server_use_ssl" {
+ default = true
+ type = bool
+ description = "Whether to use SSL when connecting to the Bosch camera"
+}
\ No newline at end of file
diff --git a/examples/terraform/singleton/MODULE.MD b/examples/terraform/singleton/MODULE.MD
new file mode 100644
index 0000000..36c1f5b
--- /dev/null
+++ b/examples/terraform/singleton/MODULE.MD
@@ -0,0 +1,39 @@
+## Requirements
+
+| Name | Version |
+|---------------------------------------------------------------------------|---------|
+| [terraform](#requirement\_terraform) | >= 1.5 |
+| [keyfactor](#requirement\_keyfactor) | >=2.1.5 |
+
+## Providers
+
+| Name | Version |
+|---------------------------------------------------------------------|---------|
+| [keyfactor](#provider\_keyfactor) | 2.1.11 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
+| [keyfactor_certificate_store.bosch_camera_store](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/resources/certificate_store) | resource |
+| [keyfactor_agent.universal_orchestrator](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/data-sources/agent) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|:--------:|
+| [camera\_ip](#input\_camera\_ip) | The IP address of the Camera. Example: `192.167.231.174:44444`. Include the port if necessary. | `string` | n/a | yes |
+| [camera\_serial\_number](#input\_camera\_serial\_number) | Enter the Serial Number of the camera e.g. `068745431065110085`. | `string` | n/a | yes |
+| [inventory\_schedule](#input\_inventory\_schedule) | How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update. | `string` | `"12h"` | no |
+| [orchestrator\_name](#input\_orchestrator\_name) | The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command | `string` | n/a | yes |
+| [server\_password](#input\_server\_password) | The password to authenticate to the Bosch camera | `string` | n/a | yes |
+| [server\_use\_ssl](#input\_server\_use\_ssl) | Whether to use SSL when connecting to the Bosch camera | `bool` | `true` | no |
+| [server\_username](#input\_server\_username) | The username to authenticate to the Bosch camera | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
diff --git a/examples/terraform/singleton/Makefile b/examples/terraform/singleton/Makefile
new file mode 100644
index 0000000..1db769c
--- /dev/null
+++ b/examples/terraform/singleton/Makefile
@@ -0,0 +1,40 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+.DEFAULT_GOAL := help
+
+##@ Utility
+help: ## Display this help
+ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+deps: ## Install deps for macos
+ @brew install pre-commit tflint terraform terraform-docs
+
+docs: ## Run terraform-docs to update module docs.
+ @terraform-docs markdown . > MODULE.MD
+ @terraform-docs markdown table --output-file README.md --output-mode inject .
+
+lint: ## Run tflint
+ @tflint
+
+validate: ## Run terraform validate
+ @terraform init --upgrade
+ @terraform validate
+
+precommit/add: ## Install pre-commit hook
+ @pre-commit install
+
+precommit/remove: ## Uninstall pre-commit hook
+ @pre-commit uninstall
+
diff --git a/examples/terraform/singleton/README.md b/examples/terraform/singleton/README.md
new file mode 100644
index 0000000..a22538c
--- /dev/null
+++ b/examples/terraform/singleton/README.md
@@ -0,0 +1,68 @@
+# Single BoschIPCamera Store Creation Example
+
+This is an example of how to create a single camera store in Keyfactor Command using the Keyfactor Terraform provider.
+
+## Pre-requisites
+
+- Terraform is installed on the machine running the Terraform code
+- The Keyfactor Terraform provider is installed and configured to communicate to Keyfactor Command. Review
+ the [Keyfactor provider documentation](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs)
+ for more information.
+- The `BIPCamera` store type is already created in Keyfactor Command. See
+ the [Extension specific documentation](https://github.com/Keyfactor/bosch-ipcamera-orchestrator?tab=readme-ov-file#store-type-configuration)
+ for more information.
+- An orchestrator with the BoschIPCamera extension is registered and approved in Keyfactor Command.
+
+## Usage
+
+Modify the `example.tfvars` file to include the necessary information for your environment. Alternatively Terraform will
+prompt for each input if no value is provided.
+
+```bash
+terraform init
+terraform plan
+terraform apply
+```
+
+
+
+## Requirements
+
+| Name | Version |
+|---------------------------------------------------------------------------|---------|
+| [terraform](#requirement\_terraform) | >= 1.5 |
+| [keyfactor](#requirement\_keyfactor) | >=2.1.5 |
+
+## Providers
+
+| Name | Version |
+|---------------------------------------------------------------------|---------|
+| [keyfactor](#provider\_keyfactor) | 2.1.11 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
+| [keyfactor_certificate_store.bosch_camera_store](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/resources/certificate_store) | resource |
+| [keyfactor_agent.universal_orchestrator](https://registry.terraform.io/providers/keyfactor-pub/keyfactor/latest/docs/data-sources/agent) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|:--------:|
+| [camera\_ip](#input\_camera\_ip) | The IP address of the Camera. Example: `192.167.231.174:44444`. Include the port if necessary. | `string` | n/a | yes |
+| [camera\_serial\_number](#input\_camera\_serial\_number) | Enter the Serial Number of the camera e.g. `068745431065110085`. | `string` | n/a | yes |
+| [inventory\_schedule](#input\_inventory\_schedule) | How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update. | `string` | `"12h"` | no |
+| [orchestrator\_name](#input\_orchestrator\_name) | The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command | `string` | n/a | yes |
+| [server\_password](#input\_server\_password) | The password to authenticate to the Bosch camera | `string` | n/a | yes |
+| [server\_use\_ssl](#input\_server\_use\_ssl) | Whether to use SSL when connecting to the Bosch camera | `bool` | `true` | no |
+| [server\_username](#input\_server\_username) | The username to authenticate to the Bosch camera | `string` | n/a | yes |
+
+## Outputs
+
+No outputs.
+
\ No newline at end of file
diff --git a/examples/terraform/singleton/agents.tf b/examples/terraform/singleton/agents.tf
new file mode 100644
index 0000000..6406bae
--- /dev/null
+++ b/examples/terraform/singleton/agents.tf
@@ -0,0 +1,17 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+data "keyfactor_agent" "universal_orchestrator" {
+ agent_identifier = var.orchestrator_name
+}
\ No newline at end of file
diff --git a/examples/terraform/singleton/example.tfvars b/examples/terraform/singleton/example.tfvars
new file mode 100644
index 0000000..08ff615
--- /dev/null
+++ b/examples/terraform/singleton/example.tfvars
@@ -0,0 +1,21 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+# UNCOMMENT AND FILL IN THE FOLLOWING VARIABLES:
+
+# orchestrator_name="my-uo-client-machine-name"
+# server_username="camera_username"
+# server_password="camera_password"
+# camera_serial_number="068745431065110085"
+# camera_ip="192.167.231.174:44444"
diff --git a/examples/terraform/singleton/main.tf b/examples/terraform/singleton/main.tf
new file mode 100644
index 0000000..7c0c3ea
--- /dev/null
+++ b/examples/terraform/singleton/main.tf
@@ -0,0 +1,24 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+resource "keyfactor_certificate_store" "bosch_camera_store" {
+ client_machine = var.camera_ip
+ store_path = var.camera_serial_number
+ agent_identifier = data.keyfactor_agent.universal_orchestrator.agent_identifier
+ store_type = "BIPCamera" # Must exist in KeyFactor Command
+ server_username = var.server_username
+ server_password = var.server_password
+ server_use_ssl = var.server_use_ssl
+ inventory_schedule = var.inventory_schedule
+}
diff --git a/examples/terraform/singleton/providers.tf b/examples/terraform/singleton/providers.tf
new file mode 100644
index 0000000..28d243c
--- /dev/null
+++ b/examples/terraform/singleton/providers.tf
@@ -0,0 +1,26 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+terraform {
+ required_version = ">= 1.5"
+ required_providers {
+ keyfactor = {
+ source = "keyfactor-pub/keyfactor"
+ version = ">=2.1.5"
+ }
+ }
+}
+provider "keyfactor" {
+
+}
diff --git a/examples/terraform/singleton/variables.tf b/examples/terraform/singleton/variables.tf
new file mode 100644
index 0000000..be24cb8
--- /dev/null
+++ b/examples/terraform/singleton/variables.tf
@@ -0,0 +1,50 @@
+# Copyright 2024 Keyfactor
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# 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.
+
+variable "orchestrator_name" {
+ type = string
+ description = "The name or GUID of the orchestrator that has been registered and approved in Keyfactor Command"
+}
+
+variable "camera_serial_number" {
+ type = string
+ description = "Enter the Serial Number of the camera e.g. `068745431065110085`."
+}
+
+variable "camera_ip" {
+ type = string
+ description = "The IP address of the Camera. Example: `192.167.231.174:44444`. Include the port if necessary."
+}
+
+variable "server_username" {
+ type = string
+ sensitive = true
+ description = "The username to authenticate to the Bosch camera"
+}
+variable "server_password" {
+ type = string
+ sensitive = true
+ description = "The password to authenticate to the Bosch camera"
+}
+variable "inventory_schedule" {
+ type = string
+ description = "How often to update the inventory, valid options are number followed by 'm' for minutes, 'h' for hours, '1d' for daily, or 'immediate' for immediate inventory update."
+ default = "12h"
+}
+
+variable "server_use_ssl" {
+ default = true
+ type = bool
+ description = "Whether to use SSL when connecting to the Bosch camera"
+}
\ No newline at end of file
diff --git a/integration-manifest.json b/integration-manifest.json
index ec8de84..0d3acbb 100644
--- a/integration-manifest.json
+++ b/integration-manifest.json
@@ -35,14 +35,14 @@
{
"Name": "Bosch IP Camera",
"ShortName": "BIPCamera",
- "Capability": "BIPCamera",
+ "Capability": "BoschIpCamera",
"LocalStore": false,
"SupportedOperations": {
- "Add": true,
+ "Add": false,
"Create": false,
"Discovery": false,
"Enrollment": true,
- "Remove": true
+ "Remove": false
},
"Properties": [
{