Outshift Logo

INSIGHTS

17 min read

Blog thumbnail
Published on 07/26/2022
Last updated on 03/21/2024

Lessons Learned from Using AWS Cloud Directory

Share

There are various ways of representing and managing organizational hierarchies and users, and several common tools used to do so. Some of the popular solutions include Microsoft's Active Directory(AD) and LDAP(Lightweight Directory Access Protocol) based services such as Open-LDAP. However, setting up and managing any of these can be complicated, and requires advanced DevOps skills to make deployments secure, highly available and backed up. AWS_Cloud1
AWS Directory Service
Cloud platforms such as AWS offer managed solutions that take most of the headache off the process by managing all the DevOps aspects mentioned above. AWS offers several types of directories including a managed Microsoft AD service, A Linux SAMBA -based (an open-source implementation of the SMB — Server Message Block — protocol) simple directory service and the Cognito user pool — a service used to define user pools that can be used to authenticate users into web or other applications. Alongside these, Amazon offers Cloud Directory, which is a simplified multi-tenant directory-based store. This post talks about what Amazon Cloud Directory is and what its main concepts are with GUI, CLI and Go code usage examples. It is important to note, that despite the fact the Cloud Directory is easier to understand and use than AD or LDAP, it hasn't gained popularity and there seems to be no support community around it. The only helpful resource outside AWS's documentation is the AWS Directory Services forum that mainly deals with the other solutions and hardly responds to questions regarding Cloud Directory. While researching Cloud Directory, it became apparent that the provided documentation is lacking, and more often than not, the only way to understand an object/request format was to dive into the AWS SDK source code.

What is AWS Cloud Directory?

To quote AWS's documentation: “Amazon Cloud Directory is a highly available multi-tenant directory-based store in AWS. These directories scale automatically to hundreds of millions of objects as needed for applications.” Cloud Directory is a directory store built on a simple graph structure with a customizable schema. One can create objects to which attributes can be assigned, and can define connections/links between the objects. The graph structure can be traversed by following the links (e.g. listing children or parents) to find requested objects. In addition, indices can be used to quickly locate objects by attributes. Cloud Directories are subject to various limitations as described here. Note, that although the classic usage of a directory would be holding organizational information, which is the example we use throughout this post, it can be used to hold any type of hierarchic or graph-based information by defining the proper schemas.

What is a Schema?

A schema is a JSON file that includes Facets and Typed Link Facets. A Facet defines the set of attributes that make up a specific type of object (a node in the directory graph), and includes data types and rules such as min/max (length for string fields or value for number fields, etc.), whether or not the attribute is required or mutable, etc. Typed Link Facets are essentially the same for the links between objects. The full format specifications can be found here. A new object must conform to at least one of the facets defined in the applied schemas. Multiple schemas can be applied to the same Cloud Directory instance. Schemas are versioned and can be upgraded to newer versions. Schemas start in development mode and that is the only mode in which they can be modified. In order to apply a schema to a directory, it first has to be published with a version, at which point it becomes immutable. When applied to a directory, the schema is copied into the directory. This copy has its own ARN (AWS Resource Name) and is considered an Applied schema. Even though an applied schema is said to be immutable, you can still add new facets and non-required attributes by upgrading to a new version of the schema. Once a schema is applied, it cannot be removed from the directory.

Creating a New Schema

AWS_Cloud2
AWS Cloud Directory Schemas List
The easiest way to create a new schema is from the AWS console. Just go into the “Schemas” section of the Cloud Directory console and click on “Upload new schema” on the top right.
AWS_Cloud3
Upload New Cloud Directory Schema
Fill in the name of the new schema and select the JSON file containing your schema data. Finally, click on the “Upload” button. Here is an example of a full schema:
{
  "facets": {
    "organization": {
      "facetAttributes": {
        "name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      },
      "objectType": "NODE"
    },
    "organizational_unit": {
      "facetAttributes": {
        "region": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": true,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "32"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "ou_id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      },
      "objectType": "NODE"
    },
    "department": {
      "facetAttributes": {
        "account_id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      },
      "objectType": "LEAF_NODE"
    },
    "user": {
      "facetAttributes": {
        "user_status": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "region": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": true,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "32"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "last_name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "display_name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "middle_name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "locale": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "mobile_phone_number": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "address (country)": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "first_name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "email": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "username": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "user_id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      },
      "objectType": "LEAF_NODE"
    },
    "organization_user": {
      "facetAttributes": {
        "employee_id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "organization_id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "title": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "NOT_REQUIRED"
        },
        "department": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      },
      "objectType": "LEAF_NODE"
    },
    "group": {
      "facetAttributes": {
        "name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "ARN": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      }
    },
    "role": {
      "facetAttributes": {
        "name": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "id": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        },
        "ARN": {
          "attributeDefinition": {
            "attributeType": "STRING",
            "isImmutable": false,
            "attributeRules": {
              "nameLength": {
                "parameters": {
                  "min": "1",
                  "max": "1024"
                },
                "ruleType": "STRING_LENGTH"
              }
            }
          },
          "requiredBehavior": "REQUIRED_ALWAYS"
        }
      }
    },
    "indices": {
      "facetAttributes": {},
      "objectType": "NODE"
    },
    "organizations": {
      "facetAttributes": {},
      "objectType": "NODE"
    },
    "groups": {
      "facetAttributes": {},
      "objectType": "NODE"
    },
    "roles": {
      "facetAttributes": {},
      "objectType": "NODE"
    }
  },
  "typedLinkFacets": {
    "member": {
      "facetAttributes": {},
      "identityAttributeOrder": []
    },
    "group_member": {
      "facetAttributes": {},
      "identityAttributeOrder": []
    },
    "assigned": {
      "facetAttributes": {},
      "identityAttributeOrder": []
    }
  }
}
To Publish a schema, choose it from the schema list and select “Publish” from the “Actions” menu on the top right.
AWS_Cloud4
Publish Schema
Fill in the version of your schema and click on “Publish”. The AWS CLI can also be used to create and publish a new schema:
aws clouddirectory create-schema -name "MySchema"
You get back the ARN of the new schema:
{
	"SchemaArn": "arn:aws:clouddirectory:eu-west-1:079349112641:schema/development/MySchema"
}
Now you can put the schema JSON data into the new schema:
aws clouddirectory put-schema-from-json -schema-arn="arn:aws:clouddirectory:eu-west-1:079349112641:schema/development/MySchema" \
  -document '{"facets":{"test":{"facetAttributes":{"attr 1":{"attributeDefinition":{"attributeType":"STRING"},"requiredBehavior":"REQUIRED_ALWAYS"}}}}}'
Again, you get back the ARN of the schema. Finally, you can publish your schema:
aws clouddirectory publish-schema -development-schema-arn="arn:aws:clouddirectory:eu-west-1:079349112641:schema/development/MySchema" \
  -schema-version "1.0"
And you get back the ARN for the published schema:
"PublishedSchemaArn": "arn:aws:clouddirectory:eu-west-1:079349112641:schema/published/MySchema/1.0"
As can be seen, the only way to specify the schema data using the CLI is directly on the command-line, which can be very limiting. Now you have two schemas in your schema list, the development schema, and the published schema.

Objects

Objects are nodes in the directory graph. They have a type, which is defined by the facets applied to them, and an Id. Objects can be linked to other objects by using Link Facets, which are the edges within the graph. It is very important to note, that creating objects in the directory doesn't automatically attach them to the directory graph! There's an optional field in the create request to specify the parent object, but it is very easy to miss. This means that the only initial way to find a newly created object is by using its Id. If you lose this Id, your object will become a space-wasting zombie. Remember that your directory has limited space, so space management is critical! The only way to find a zombie object is to go through the AWS trace logs in CloudTrail and find the log entry for the create operation with the new object's Id. I recommend planning your directory structure in advance so that when you create a new object, you already know where in the graph you want to attach it to and attach it there while or immediately after creating it. Once an object is attached, you can also find it using a path selector from the graph's root to the object. Another note to remember is that the root of the directory graph is, in itself, an object in the graph.

Indices

Indices allow you to search for objects within your directory. Unlike database indices, Cloud Directory indices require explicit association of objects. When you create a new index, it is empty. You need to manually attach objects, one by one, to the index to be able to search for them. Moreover, an index is just another object in your directory so, like every other object, you must either remember its Id or attach it to your graph. I recommend creating an “indices” object (branch) under the graph’s root and hanging all the indices under this branch. This way you can easily get to your index by following the path to it from the root:
aws clouddirectory list-object-children -directory-arn="arn:aws:clouddirectory:us-west-2:079349112641:directory/Ae57WewFEE2kpkjM_9M1SsM" \
  -object-reference Selector=/indices
For which you get:
{
	"Children": {
		"org_index": "AQHue1nsBRBNpKZIzP_TNUrDz7CQl-YARV65xjvbZig-eg",
		"ou_index": "AQHue1nsBRBNpKZIzP_TNUrDXYg_quMxSsuc1tArxkJneA",
		"user_index": "AQHue1nsBRBNpKZIzP_TNUrDxVDEjQ6dTqO5_WZ180rG1A"
	}
}
While an index is an object in the directory, it is a special one so listing items under an index is done using the “list-index” command instead of the “list-object-children” command:
aws clouddirectory list-index -directory-arn="arn:aws:clouddirectory:us-west-2:079349112641:directory/Ae57WewFEE2kpkjM_9M1SsM" \
  -index-reference Selector=/indexes/org_index
And you get:
{
	"IndexAttachments": [{
		"IndexedAttributes": [{
			"Key": {
				"SchemaArn": "arn:aws:clouddirectory:eu-west-1:079349112641:directory/AeWj_9vukUfkjFGuk834kt0/schema/MyNewSchema/1.0",
				"FacetName": "organization",
				"Name": "name"
			},
			"Value": {
				"StringValue": "MySampleOrg"
			}
		}],
		"ObjectIdentifier": "AQHlo__b7pFH5IxRrpPN-JLdeWittEQ2RK6ke-qayaOxJw"
	}]
}
In this output we see just a single object that has been attached to the index. For each object we get the list of set attributes. Each attribute has a “Key” that contains the ARN of the schema in which the attribute is defined, the facet within that schema and the attribute’s name. We also get a “Value” for the attribute with the attribute’s type and value.

Creating a Cloud Directory

The simplest way to deploy a Cloud Directory instance is to log into the AWS console and navigate to the Directory Service console. Then, select the “Directories” link under the “Cloud Directory” section from the left sidebar.
AWS_Cloud5
AWS Cloud Directory Console
Now, click the “Set up Cloud Directory” button.
AWS_Cloud6
Create Cloud Directory
First, choose a name for the new directory, and then the type of schema to start with. The Managed schema is a simple schema with a dynamic facet and a dynamicTypedLinkFacet, which means you can put whatever you want into your new objects. While this allows you to quickly start building, it is limited in the sense that the directory will not be able to type check your objects or index them. Choosing the Sample schema option will allow you to apply one of three preexisting schemas that are often used to build organizational hierarchies: “device”, “organization” and “user”. Finally, Custom, let's you apply your own custom schema that has already been uploaded and published. When you click the "Next” button, you will get a review screen showing a summary of the configuration for the new Cloud Directory instance, as well as a notification regarding pricing. With Cloud Directory you pay as you go, starting with a free tier service and moving into paying schemes over time and as you grow.
AWS_Cloud7
New Cloud Directory Review
Finally, you can click the “Create” button to create your new Cloud Directory instance. The AWS console allows you to also create a directory with an existing schema directly from the Schemas section. You simply select your schema and select “Create directory from schema” form the “Actions” menu on the top right. You get the same screen as before, but this time “Custom schema” is selected, and your new schema is selected from the schema list. Fill any other required details and click on “Next”. If your schema was not yet published, you will now be asked to fill in the Major and Minor versions for your schema before giving you the review screen upon clicking “Next”, where you can now also preview the schema. Finally, click on “Create” to create your directory. You can create a new Cloud Directory from the AWS CLI using the create-directory command. Please note, that once you apply a schema to a directory, either by specifying the published schema to use while creating the directory or by applying a published schema to an existing directory, Cloud Directory will copy your schema into the directory and will give you back an ARN pointing to that copy, which is now an Applied Schema.

Code Example

Here is a Go code example that shows how to create and publish a schema, and how to create a directory using the published schema, thereby also creating an applied schema. Next, we create an “indices” branch under the root of the directory and then create a new index over the “name” attribute of the “organization” facet and hang it under that branch. Finally, we create a new organization object, hang it under the root and attach it to the index.
package main

import (
	"fmt"
	"io/ioutil"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/clouddirectory"
)

func main() {

	// Static credentials from environment variables
	id := os.Getenv("AWS_ACCESS_KEY_ID")
	secret := os.Getenv("AWS_SECRET_ACCESS_KEY")
	credentials := credentials.NewStaticCredentials(id, secret, "")

	// AWS session
	region := os.Getenv("AWS_REGION")
	session := session.Must(session.NewSession(
		&aws.Config{
			Region:      aws.String(region),
			Credentials: credentials,
			MaxRetries:  aws.Int(5),
		},
	))

	// Cloud Directory session
	cloudDirectorySession := clouddirectory.New(session)

	// Create the schema
	createSchemaInput := &clouddirectory.CreateSchemaInput{
		Name: aws.String("MyNewSchema"),
	}

	createSchemaOutput, err := cloudDirectorySession.CreateSchema(createSchemaInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Created new schema: %v\n", createSchemaOutput)

	// read the schema
	data, err := ioutil.ReadFile("MySchema.json")
	if err != nil {
		panic(err)
	}
	schemaData := string(data)

	// upload the schema data
	putSchemaInput := &clouddirectory.PutSchemaFromJsonInput{
		SchemaArn: createSchemaOutput.SchemaArn,
		Document:  &schemaData,
	}
	putSchemaOutput, err := cloudDirectorySession.PutSchemaFromJson(putSchemaInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Added schema data: %v\n", putSchemaOutput)

	// publish the schema
	publishSchemaInput := &clouddirectory.PublishSchemaInput{
		Name:                 aws.String("MyNewSchema"),
		DevelopmentSchemaArn: putSchemaOutput.Arn,
		Version:              aws.String("1.0"),
	}

	publishSchemaOutput, err := cloudDirectorySession.PublishSchema(publishSchemaInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Published schema: %v\n", publishSchemaOutput)

	// Create a directory
	createDirectoryInput := &clouddirectory.CreateDirectoryInput{
		Name:      aws.String("MyDirectory"),
		SchemaArn: publishSchemaOutput.PublishedSchemaArn,
	}

	createDirectoryOutput, err := cloudDirectorySession.CreateDirectory(createDirectoryInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Created new directory: %v\n", createDirectoryOutput)

	// Create an Index holder under the root
	createBranchInput := clouddirectory.CreateObjectInput{
		DirectoryArn: createDirectoryOutput.DirectoryArn,
		ParentReference: &clouddirectory.ObjectReference{
			Selector: aws.String("/"),
		},
		LinkName: aws.String("indices"),
		SchemaFacets: []*clouddirectory.SchemaFacet{
			{
				FacetName: aws.String("indices"),
				SchemaArn: createDirectoryOutput.AppliedSchemaArn,
			},
		},
	}
	createBranchOutput, err := cloudDirectorySession.CreateObject(&createBranchInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Created new branch: %v\n", createBranchOutput)

	// Create an index and hang under the holder
	createIndexInput := clouddirectory.CreateIndexInput{
		DirectoryArn: createDirectoryOutput.DirectoryArn,
		IsUnique:     aws.Bool(true),
		LinkName:     aws.String("org_index"),
		OrderedIndexedAttributeList: []*clouddirectory.AttributeKey{
			{
				FacetName: aws.String("organization"),
				Name:      aws.String("name"),
				SchemaArn: createDirectoryOutput.AppliedSchemaArn,
			},
		},
		ParentReference: &clouddirectory.ObjectReference{
			Selector: aws.String("/indices"),
		},
	}

	createIndexOutput, err := cloudDirectorySession.CreateIndex(&createIndexInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Created new Index: %v\n", createIndexOutput)

	// Create an object and hang under the root
	createOrganizationInput := clouddirectory.CreateObjectInput{
		DirectoryArn: createDirectoryOutput.DirectoryArn,
		ParentReference: &clouddirectory.ObjectReference{
			Selector: aws.String("/"),
		},
		LinkName: aws.String("MyOrganization"),
		SchemaFacets: []*clouddirectory.SchemaFacet{
			{
				FacetName: aws.String("organization"),
				SchemaArn: createDirectoryOutput.AppliedSchemaArn,
			},
		},
		ObjectAttributeList: []*clouddirectory.AttributeKeyAndValue{
			&clouddirectory.AttributeKeyAndValue{
				Key: &clouddirectory.AttributeKey{
					FacetName: aws.String("organization"),
					Name:      aws.String("name"),
					SchemaArn: createDirectoryOutput.AppliedSchemaArn,
				},
				Value: &clouddirectory.TypedAttributeValue{
					StringValue: aws.String("MySampleOrg"),
				},
			},
		},
	}
	createOrganizationOutput, err := cloudDirectorySession.CreateObject(&createOrganizationInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Created new object: %v\n", createOrganizationOutput)

	// Attach the object to the index
	attachToIndexInput := &clouddirectory.AttachToIndexInput{
		DirectoryArn: createDirectoryOutput.DirectoryArn,
		IndexReference: &clouddirectory.ObjectReference{
			Selector: aws.String("
<pre wp-pre-tag-10=""></pre>
quot; + *createIndexOutput.ObjectIdentifier),
		},
		TargetReference: &clouddirectory.ObjectReference{
			Selector: aws.String("
<pre wp-pre-tag-10=""></pre>
quot; + *createOrganizationOutput.ObjectIdentifier),
		},
	}

	attachToIndexOutput, err := cloudDirectorySession.AttachToIndex(attachToIndexInput)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Attached object to index: %v\n", attachToIndexOutput)
}

Transactions

Cloud Directory doesn't support sessions or transactions in the traditional sense. Since each call to Cloud Directory is atomic, you have the option to batch multiple operations into a single call, thereby achieving the effect of a session or a transaction. To do this you can use the batch-read and batch-write commands using the CLI, or the BatchRead and BatchWrite Go functions accordingly.

Summary

AWS Cloud Directory is a simple graph-based directory that allows you to store typed objects, traverse the graph by listing the children and parents of objects, create indices to index objects and then search for the objects using those indices. It is conceptually simple to use but as there is little to no community support, it can be hard to understand how everything comes together. I hope this post helps you, future Cloud Directory users, understand the basic concepts and build your applications on top of Cloud Directory.
Subscribe card background
Subscribe
Subscribe to
the Shift!

Get emerging insights on emerging technology straight to your inbox.

Unlocking Multi-Cloud Security: Panoptica's Graph-Based Approach

Discover why security teams rely on Panoptica's graph-based technology to navigate and prioritize risks across multi-cloud landscapes, enhancing accuracy and resilience in safeguarding diverse ecosystems.

thumbnail
I
Subscribe
Subscribe
 to
the Shift
!
Get
emerging insights
on emerging technology straight to your inbox.

The Shift keeps you at the forefront of cloud native modern applications, application security, generative AI, quantum computing, and other groundbreaking innovations that are shaping the future of technology.

Outshift Background