diff --git a/README.md b/README.md
index 92b2279e3ebec9be2a7e1b554c619003693675fb..0a78b120b707dea60cc9f2c012031df15e02fdd3 100644
--- a/README.md
+++ b/README.md
@@ -3,12 +3,7 @@
 * Install [terraform](https://www.terraform.io/downloads.html) 1.0 or greater
 * Configure some application credentials in the [RC Openstack dashboard](https://dashboard.cloud.rc.uab.edu/identity/application_credentials/)
 * Add a key pair (in the [Key Pairs](https://dashboard.cloud.rc.uab.edu/project/key_pairs) section)
-* Add your private key to an ssh-agent session:
 
-```bash
-eval $(ssh-agent)
-ssh-add ~/path/to/private/key
-```
 
 # Infrastructure deployment
 
@@ -19,7 +14,7 @@ ssh-add ~/path/to/private/key
 
 # Ceph setup
 
-1. Log into the admin node with `ssh -i ~/.ssh-keys/openstack-fedora-vm -o GlobalKnownHostsFile=/dev/null -o StrictHostKeyChecking=no sles@$(terraform output -raw admin_ip_address)`
+1. Log into the admin node with `ssh -i ${PRIVATE_KEY_PATH} -o GlobalKnownHostsFile=/dev/null -o StrictHostKeyChecking=no sles@$(terraform output -raw admin_ip_address)`
 2. `sudo salt-key -F` to show nodes waiting to be accept into the salt-master; you may need to wait a bit before all nodes show up
 3. `sudo salt-key --accept-all` to accept all nodes
 4. `sudo salt \* saltutil.sync_all` to sync all the nodes (if there's an error, wait a moment and try again)
@@ -30,6 +25,7 @@ ssh-add ~/path/to/private/key
 9. `sudo ceph-salt apply`
 10. access the web interface (in the terraform outputs with `terraform output web_ip_address`)
 
+
 # Variables
 
 | Variable                | Type         | Required | Default              | Description                                                                       |
@@ -48,4 +44,5 @@ ssh-add ~/path/to/private/key
 | `sles_reg_email`        | string       | yes      |                      | email for use with SUSE registration                                              |
 | `sles_ses_reg`          | string       | yes      |                      | code to register for the storage package in SUSE                                  |
 | `osd_disk_sizes`        | list(number) | no       | \[8, 8\]             | Amount/size of disks to add, in GB                                                |
+| `app_instance_count`    | number       | no       | 0                    | Additional instances to add for testing rgw, rbd, etc                             |
 
diff --git a/compute.tf b/compute.tf
index 9477ff680b6cfbedbd3f7849299fa32d20a2ba52..d7428bc8d0aef1d881f68257c10bc406795d7859 100644
--- a/compute.tf
+++ b/compute.tf
@@ -15,36 +15,6 @@ data "openstack_compute_flavor_v2" "m1_small" {
   name = "m1.small"
 }
 
-
-# template file cloud-init.yml
-
-data "template_file" "cloud_init_admin_yml" {
-  template = file("${path.module}/templates/cloud-init-admin.yml")
-  vars = {
-    sles_reg_code  = var.sles_reg_code
-    sles_reg_email = var.sles_reg_email
-    sles_ses_reg   = var.sles_ses_reg
-  }
-}
-
-data "template_file" "cloud_init_yml" {
-  template = file("${path.module}/templates/cloud-init.yml")
-  vars = {
-    sles_reg_code  = var.sles_reg_code
-    sles_reg_email = var.sles_reg_email
-    sles_ses_reg   = var.sles_ses_reg
-  }
-}
-
-# template file for cluster.json
-
-data "template_file" "cluster_json" {
-  template = file("${path.module}/templates/cluster.json")
-  vars = {
-    mon_bootstrap_ip = openstack_compute_instance_v2.mon[0].network[0].fixed_ip_v4
-  }
-}
-
 # admin node
 
 resource "openstack_compute_instance_v2" "admin" {
@@ -57,7 +27,18 @@ resource "openstack_compute_instance_v2" "admin" {
     openstack_compute_secgroup_v2.allow_ssh.name
   ]
 
-  user_data = data.template_file.cloud_init_admin_yml.rendered
+  user_data = templatefile("${path.module}/templates/cloud-init-admin.yml",
+    {
+      sles_reg_code  = var.sles_reg_code
+      sles_reg_email = var.sles_reg_email
+      sles_ses_reg   = var.sles_ses_reg
+      b64_json = base64encode(templatefile("${path.module}/templates/cluster.json", {
+        mon_bootstrap_ip = openstack_compute_instance_v2.mon[0].network[0].fixed_ip_v4
+        additional_hosts = openstack_compute_instance_v2.app.*.name
+        }
+      ))
+    }
+  )
 
   block_device {
     # this is the image to clone from
@@ -72,22 +53,16 @@ resource "openstack_compute_instance_v2" "admin" {
     uuid = openstack_networking_network_v2.public_network.id
   }
 
+  lifecycle {
+    ignore_changes = [
+      user_data # ignore changes to user_data after instance creation
+    ]
+  }
 }
 
 resource "openstack_compute_floatingip_associate_v2" "admin_association" {
   floating_ip = openstack_compute_floatingip_v2.floating_ip.address
   instance_id = openstack_compute_instance_v2.admin.id
-
-  provisioner "file" {
-    content     = data.template_file.cluster_json.rendered
-    destination = "/home/sles/cluster.json"
-
-    connection {
-      type = "ssh"
-      user = "sles"
-      host = openstack_compute_floatingip_v2.floating_ip.address
-    }
-  }
 }
 
 # OSD nodes
@@ -103,7 +78,12 @@ resource "openstack_compute_instance_v2" "osd" {
     "default"
   ]
 
-  user_data = data.template_file.cloud_init_yml.rendered
+  user_data = templatefile("${path.module}/templates/cloud-init.yml",
+    {
+      sles_reg_code  = var.sles_reg_code
+      sles_reg_email = var.sles_reg_email
+      sles_ses_reg   = var.sles_ses_reg
+  })
 
   block_device {
     # this is the image to clone from
@@ -136,20 +116,26 @@ resource "openstack_compute_instance_v2" "osd" {
   }
 }
 
-# MDS node
+# MON node
 
-resource "openstack_compute_instance_v2" "mds" {
+resource "openstack_compute_instance_v2" "mon" {
   count = 1 # TODO: add variables for this later
 
-  name      = format("mds%02d", count.index + 1)
+  name      = format("mon%02d", count.index + 1)
   image_id  = data.openstack_images_image_v2.base_image.id
   flavor_id = data.openstack_compute_flavor_v2.m1_small.id
   key_pair  = var.ssh_keypair
   security_groups = [
-    "default"
+    "default",
+    openstack_compute_secgroup_v2.allow_web_interface.name
   ]
 
-  user_data = data.template_file.cloud_init_yml.rendered
+  user_data = templatefile("${path.module}/templates/cloud-init.yml",
+    {
+      sles_reg_code  = var.sles_reg_code
+      sles_reg_email = var.sles_reg_email
+      sles_ses_reg   = var.sles_ses_reg
+  })
 
   block_device {
     # this is the image to clone from
@@ -165,24 +151,33 @@ resource "openstack_compute_instance_v2" "mds" {
   }
 }
 
-# MON node
+resource "openstack_compute_floatingip_associate_v2" "mon_association" {
+  floating_ip = openstack_compute_floatingip_v2.floating_ip_mon.address
+  instance_id = openstack_compute_instance_v2.mon[0].id
+}
 
-resource "openstack_compute_instance_v2" "mon" {
-  count = 1 # TODO: add variables for this later
 
-  name      = format("mon%02d", count.index + 1)
+# App nodes
+
+resource "openstack_compute_instance_v2" "app" {
+  count = var.app_instance_count
+
+  name      = format("app%02d", count.index + 1)
   image_id  = data.openstack_images_image_v2.base_image.id
   flavor_id = data.openstack_compute_flavor_v2.m1_small.id
   key_pair  = var.ssh_keypair
   security_groups = [
     "default",
-    openstack_compute_secgroup_v2.allow_web_interface.name
   ]
 
-  user_data = data.template_file.cloud_init_yml.rendered
+  user_data = templatefile("${path.module}/templates/cloud-init.yml",
+    {
+      sles_reg_code  = var.sles_reg_code
+      sles_reg_email = var.sles_reg_email
+      sles_ses_reg   = var.sles_ses_reg
+  })
 
   block_device {
-    # this is the image to clone from
     uuid                  = data.openstack_images_image_v2.base_image.id
     source_type           = "image"
     destination_type      = "local"
@@ -194,9 +189,3 @@ resource "openstack_compute_instance_v2" "mon" {
     uuid = openstack_networking_network_v2.public_network.id
   }
 }
-
-resource "openstack_compute_floatingip_associate_v2" "mon_association" {
-  floating_ip = openstack_compute_floatingip_v2.floating_ip_mon.address
-  instance_id = openstack_compute_instance_v2.mon[0].id
-}
-
diff --git a/templates/cloud-init-admin.yml b/templates/cloud-init-admin.yml
index 4bd808dd58bf4fe07b2ed28649fa136802a50ea9..936dfb4624d147ac8a6dd5ef1b5ca4684cad6749 100644
--- a/templates/cloud-init-admin.yml
+++ b/templates/cloud-init-admin.yml
@@ -1,5 +1,12 @@
 #cloud-config
 
+write_files:
+  - encoding: b64
+    content: ${b64_json}
+    path: /home/sles/cluster.json
+    permissions: "0644"
+    owner: sles:users
+
 runcmd:
   - sudo SUSEConnect -r ${sles_reg_code} -e ${sles_reg_email}
   - sudo SUSEConnect -p ses/7/x86_64 -r ${sles_ses_reg}
diff --git a/templates/cluster.json b/templates/cluster.json
index 685a67910bfe64b5c4895fe080f47e55e238abc0..fa13c2f26e9712c07013d8a2c09516623e594ccc 100644
--- a/templates/cluster.json
+++ b/templates/cluster.json
@@ -24,17 +24,21 @@
         "all": [
             "mon01",
             "osd02",
-            "mds01",
             "osd01",
             "osd03",
+%{ for host in additional_hosts ~}
+            "${ host }",
+%{ endfor ~}
             "admin"
         ],
         "cephadm": [
             "mon01",
             "osd02",
-            "mds01",
             "osd01",
             "osd03",
+%{ for host in additional_hosts ~}
+            "${ host }",
+%{ endfor ~}
             "admin"
         ],
         "latency": [],
diff --git a/terraform.tfvars.example b/terraform.tfvars.example
index fca2711f7c460f7a9b09fbef79fe18a4cea0c00f..acf5ace2170ca8e5deb7a3d53d463fb44e584a26 100644
--- a/terraform.tfvars.example
+++ b/terraform.tfvars.example
@@ -26,6 +26,8 @@ ssh_keypair      = "ssh_keypair_name"
 public_network_dns = ["8.8.8.8", "1.1.1.1"]
 # An array of disks to add to the OSD instances, in GB; the default creates 2 8GB disks
 #osd_disk_sizes = [8, 8]
+# Additional "application" instances to provision
+#app_instance_count = 0
 
 
 ##
@@ -33,6 +35,6 @@ public_network_dns = ["8.8.8.8", "1.1.1.1"]
 ##
 
 # suse registration details
-sles_reg_code    = "suse registration code
+sles_reg_code    = "suse registration code"
 sles_reg_email   = "suse registration email"
 sles_ses_reg     = "suse storage extension registration code"
diff --git a/variables.tf b/variables.tf
index ed696becdde912ce1635aac726ede71ddc2a2f81..9e5f74fe44604440fbf4a9eb5a84b357affc1502 100644
--- a/variables.tf
+++ b/variables.tf
@@ -75,3 +75,9 @@ variable "osd_disk_sizes" {
   default     = [8, 8]
   description = "Amount and size of disks (in GB) to add to each OSD node. By default, add two 8GB nodes"
 }
+
+variable "app_instance_count" {
+  type        = number
+  default     = 0
+  description = "Additional nodes to add for testing other features (rgw, rbd, etc)"
+}