예제 #1
0
        /// <summary>
        /// This method verifies that all of the required inputs exist within the Json file.
        /// </summary>
        /// <param name="vaultList">The KeyVault information obtained from MasterConfig.json file</param>
        /// <param name="configVaults">The Json object formed from parsing the MasterConfig.json file</param>
        public void checkJsonFields(JsonInput vaultList, JObject configVaults)
        {
            List <string> missingInputs = new List <string>();
            int           numValid      = 0;

            if (vaultList.Resources != null)
            {
                ++numValid;
            }
            else
            {
                missingInputs.Add("Resources");
            }

            int numMissing = missingInputs.Count();

            if (missingInputs.Count() == 0 && configVaults.Children().Count() != numValid)
            {
                throw new Exception($"Invalid fields in Json were defined. Only valid field is 'Resources'.");
            }
            else if (missingInputs.Count() != 0 && configVaults.Children().Count() != numValid)
            {
                throw new Exception($"Missing {string.Join(" ,", missingInputs)} in Json. Invalid fields were defined; " +
                                    $"Only valid field is 'Resources'.");
            }
            else if (missingInputs.Count() > 0)
            {
                throw new Exception($"Missing {string.Join(" ,", missingInputs)} in Json.");
            }
        }
        /// <summary>
        /// This method verifies that reading invalid Resource Fields are handled.
        /// </summary>
        public void TestCheckMissingResourceFieldsInvalid()
        {
            AccessPoliciesToYaml ap = new AccessPoliciesToYaml(true);
            string  masterConfig    = System.IO.File.ReadAllText("../../../Input/MasterConfig.json");
            JObject configVaults    = JObject.Parse(masterConfig);

            JsonInput missingResourceGroupName = createExpectedJson(new List <Resource>());

            missingResourceGroupName.Resources[0].ResourceGroups[0].ResourceGroupName = null;
            JsonInput missingSubscriptionId = createExpectedJson(new List <Resource>());

            missingSubscriptionId.Resources[1].SubscriptionId = null;
            List <Testing <JsonInput> > negativeTestMissingResourceFields = new List <Testing <JsonInput> >()
            {
                new Testing <JsonInput>(missingResourceGroupName, "Missing 'ResourceGroupName' for ResourceGroup. Invalid fields were defined; valid fields are 'ResourceGroupName' and 'KeyVaults'."),
                new Testing <JsonInput>(missingSubscriptionId, "Missing 'SubscriptionId' for Resource. Invalid fields were defined; valid fields are 'SubscriptionId' and 'ResourceGroups'.")
            };

            foreach (Testing <JsonInput> testCase in negativeTestMissingResourceFields)
            {
                try
                {
                    ap.checkMissingResourceFields(testCase.testObject, configVaults);
                    Assert.Fail();
                }
                catch (Exception e)
                {
                    Assert.AreEqual(testCase.error, e.Message);
                }
            }
        }
예제 #3
0
        public static List <KeyVaultProperties> runProgram(string[] args, bool testing)
        {
            AccessPoliciesToYaml   ap = new AccessPoliciesToYaml(testing);
            UpdatePoliciesFromYaml up = new UpdatePoliciesFromYaml(testing);

            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WriteLine("Refer to 'Log.log' for more details should an error be thrown.\n");
            Console.ResetColor();

            Console.WriteLine("Reading input files...");
            up.verifyFileExtensions(args);
            JsonInput vaultList = ap.readJsonFile(args[0]);

            Console.WriteLine("Finished!");

            Console.WriteLine("Grabbing secrets...");
            Dictionary <string, string> secrets = ap.getSecrets();

            Console.WriteLine("Finished!");

            Console.WriteLine("Creating KeyVaultManagementClient, GraphServiceClient, and AzureClient...");
            KeyVaultManagementClient kvmClient   = ap.createKVMClient(secrets);
            GraphServiceClient       graphClient = ap.createGraphClient(secrets);
            IAuthenticated           azureClient = ap.createAzureClient(secrets);

            Console.WriteLine("Finished!");;

            Console.WriteLine("Checking access and retrieving key vaults...");
            ap.checkAccess(vaultList, azureClient);
            List <KeyVaultProperties> vaultsRetrieved = ap.getVaults(vaultList, kvmClient, graphClient);

            Console.WriteLine("Finished!");

            Console.WriteLine("Reading yaml file...");
            List <KeyVaultProperties> yamlVaults = up.deserializeYaml(args[1]);

            Console.WriteLine("Finished!");

            Console.WriteLine("Updating key vaults...");
            List <KeyVaultProperties> deletedPolicies = up.updateVaults(yamlVaults, vaultsRetrieved, kvmClient, secrets, graphClient);

            Console.WriteLine("Finished!");

            Console.WriteLine("Generating DeletedPolicies yaml...");
            up.convertToYaml(deletedPolicies, args[2]);
            Console.WriteLine("Finished!");

            if (testing)
            {
                return(up.Changed);
            }
            return(null);
        }
예제 #4
0
        /// <summary>
        /// This method verifies that all of the required inputs exist for each Resource object.
        /// </summary>
        /// <param name="vaultList">The KeyVault information obtained from MasterConfig.json file</param>
        /// <param name="configVaults">The Json object formed from parsing the MasterConfig.json file</param>
        public void checkMissingResourceFields(JsonInput vaultList, JObject configVaults)
        {
            JEnumerable <JToken> resourceList = configVaults.SelectToken($".Resources").Children();

            int i = 0;

            foreach (Resource res in vaultList.Resources)
            {
                JToken jres = resourceList.ElementAt(i);

                if (res.SubscriptionId != null && res.ResourceGroups.Count() == 0 && jres.Children().Count() > 1)
                {
                    throw new Exception($"Invalid fields for Resource with SubscriptionId '{res.SubscriptionId}' were defined. Valid fields are 'SubscriptionId' and 'ResourceGroups'.");
                }
                else if (res.SubscriptionId == null && jres.Children().Count() > 0)
                {
                    throw new Exception($"Missing 'SubscriptionId' for Resource. Invalid fields were defined; valid fields are 'SubscriptionId' and 'ResourceGroups'.");
                }
                else if (res.SubscriptionId != null && res.ResourceGroups.Count() != 0)
                {
                    if (jres.Children().Count() > 2)
                    {
                        throw new Exception($"Invalid fields other than 'SubscriptionId' and 'ResourceGroups' were defined for Resource with SubscriptionId '{res.SubscriptionId}'.");
                    }

                    int j = 0;
                    foreach (ResourceGroup resGroup in res.ResourceGroups)
                    {
                        JEnumerable <JToken> groupList = jres.SelectToken($".ResourceGroups").Children();
                        JToken jresGroup = groupList.ElementAt(j);

                        if (resGroup.ResourceGroupName != null && resGroup.KeyVaults.Count() == 0 && jresGroup.Children().Count() > 1)
                        {
                            throw new Exception($"Invalid fields for ResourceGroup with ResourceGroupName '{resGroup.ResourceGroupName}' were defined. " +
                                                $"Valid fields are 'ResourceGroupName' and 'KeyVaults'.");
                        }
                        else if (resGroup.ResourceGroupName == null && jresGroup.Children().Count() > 0)
                        {
                            throw new Exception("Missing 'ResourceGroupName' for ResourceGroup. Invalid fields were defined; valid fields are 'ResourceGroupName' and 'KeyVaults'.");
                        }
                        else if (resGroup.ResourceGroupName != null && resGroup.KeyVaults.Count() != 0 && jresGroup.Children().Count() > 2)
                        {
                            throw new Exception($"Invalid fields other than 'ResourceGroupName' and 'KeyVaults' were defined for ResourceGroup " +
                                                $"with ResourceGroupName '{resGroup.ResourceGroupName}'.");
                        }
                        ++j;
                    }
                }
                ++i;
            }
        }
예제 #5
0
        /// <summary>
        /// This method reads in and deserializes the json input file.
        /// </summary>
        /// <param name="jsonDirectory">The json file path</param>
        /// <returns>A JsonInput object that stores the json input data</returns>
        public JsonInput readJsonFile(string jsonDirectory)
        {
            log.Info("Reading in Json file....");
            try
            {
                string    masterConfig = System.IO.File.ReadAllText(jsonDirectory);
                JsonInput vaultList    = JsonConvert.DeserializeObject <JsonInput>(masterConfig);

                JObject configVaults = JObject.Parse(masterConfig);
                checkJsonFields(vaultList, configVaults);
                checkMissingResourceFields(vaultList, configVaults);
                log.Info("Json file read!");
                return(vaultList);
            }
            catch (Exception e)
            {
                log.Error("DeserializationFail", e);
                log.Debug("Refer to https://github.com/microsoft/Managing-RBAC-in-Azure/blob/master/Config/MasterConfigExample.json for questions on formatting and inputs. Ensure that you have all the required fields with valid values, then try again.");
                Exit(e.Message);
                return(null);
            }
        }
        /// <summary>
        /// This method creates an expected json that is used for testing purposes.
        /// </summary>
        /// <param name="resources"> List of Resources </param>
        /// <returns>The expected deserialized JsonInput</returns>
        private JsonInput createExpectedJson(List <Resource> resources)
        {
            var expectedJson = new JsonInput();

            expectedJson.Resources = resources;


            if (resources != null)
            {
                var res1 = new Resource();
                res1.SubscriptionId = "sample1";
                var g1 = new ResourceGroup();
                g1.ResourceGroupName = "group a";
                g1.KeyVaults.Add("VaultA");
                var g2 = new ResourceGroup();
                g2.ResourceGroupName = "group b";
                g2.KeyVaults.Add("VaultB");
                res1.ResourceGroups.Add(g1);
                res1.ResourceGroups.Add(g2);
                expectedJson.Resources.Add(res1);

                var res2 = new Resource();
                res2.SubscriptionId = "sample2";
                expectedJson.Resources.Add(res2);

                var res3 = new Resource();
                res3.SubscriptionId = "sample3";
                g1 = new ResourceGroup();
                g1.ResourceGroupName = "RBACTest3";
                g1.KeyVaults.Add("RBACTestVault1");
                g1.KeyVaults.Add("RBACTestVault2");
                res3.ResourceGroups.Add(g1);
                expectedJson.Resources.Add(res3);
            }
            return(expectedJson);
        }
        /// <summary>
        /// This method reads in a Json config file and converts it into a serialized list of KeyVaults that are displayed in a Yaml file.
        /// </summary>
        public static void Main(string[] args)
        {
            AccessPoliciesToYaml ap = new AccessPoliciesToYaml(false);

            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WriteLine("Refer to 'Log.log' for more details should an error be thrown.\n");
            Console.ResetColor();

            Console.WriteLine("Reading input file...");
            ap.verifyFileExtensions(args);
            JsonInput vaultList = ap.readJsonFile(args[0]);

            Console.WriteLine("Finished!");

            Console.WriteLine("Grabbing secrets...");
            Dictionary <string, string> secrets = ap.getSecrets();

            Console.WriteLine("Finished!");

            Console.WriteLine("Creating KeyVaultManagementClient, GraphServiceClient, and AzureClient...");
            KeyVaultManagementClient kvmClient   = ap.createKVMClient(secrets);
            GraphServiceClient       graphClient = ap.createGraphClient(secrets);
            IAuthenticated           azureClient = ap.createAzureClient(secrets);

            Console.WriteLine("Finished!");;

            Console.WriteLine("Checking access and retrieving key vaults...");
            ap.checkAccess(vaultList, azureClient);
            List <KeyVaultProperties> vaultsRetrieved = ap.getVaults(vaultList, kvmClient, graphClient);

            Console.WriteLine("Finished!");

            Console.WriteLine("Generating YAML output...");
            ap.convertToYaml(vaultsRetrieved, args[1]);
            Console.WriteLine("Finished!");
        }
예제 #8
0
        /// <summary>
        /// This method retrieves each of the KeyVaults specified in "vaultList".
        /// </summary>
        /// <param name="vaultList">The data obtained from deserializing json file</param>
        /// <param name="kvmClient">The KeyVaultManagementClient containing Vaults</param>
        /// <param name="graphClient">The Microsoft GraphServiceClient for obtaining display names</param>
        /// <returns>The list of KeyVaultProperties containing the properties of each KeyVault</returns>
        public List <KeyVaultProperties> getVaults(JsonInput vaultList, KeyVaultManagementClient kvmClient, GraphServiceClient graphClient)
        {
            log.Info("Getting Vaults...");
            List <Vault> vaultsRetrieved = new List <Vault>();

            foreach (Resource res in vaultList.Resources)
            {
                log.Info($"Entering SubscriptionID: {res.SubscriptionId}");

                // Associates the client with the subscription
                kvmClient.SubscriptionId = res.SubscriptionId;

                // Retrieves all KeyVaults at the Subscription scope
                if (res.ResourceGroups.Count == 0)
                {
                    vaultsRetrieved = getVaultsAllPages(kvmClient, vaultsRetrieved);
                }
                else
                {
                    bool notFound = false;
                    foreach (ResourceGroup resGroup in res.ResourceGroups)
                    {
                        log.Info($"Entering ResourceGroup: {resGroup.ResourceGroupName}");
                        // If the Subscription is not found, then do not continue looking for vaults in this subscription
                        if (notFound)
                        {
                            break;
                        }

                        // Retrieves all KeyVaults at the ResourceGroup scope
                        if (resGroup.KeyVaults.Count == 0)
                        {
                            vaultsRetrieved = getVaultsAllPages(kvmClient, vaultsRetrieved, resGroup.ResourceGroupName);
                        }
                        // Retrieves all KeyVaults at the Resource scope
                        else
                        {
                            foreach (string vaultName in resGroup.KeyVaults)
                            {
                                log.Info($"Entering VaultName: {vaultName}");
                                try
                                {
                                    vaultsRetrieved.Add(kvmClient.Vaults.Get(resGroup.ResourceGroupName, vaultName));
                                }
                                catch (CloudException e)
                                {
                                    log.Error(e.Message);
                                    ConsoleError(e.Message);
                                    if (e.Body.Code == "SubscriptionNotFound")
                                    {
                                        notFound = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            List <KeyVaultProperties> keyVaultsRetrieved = new List <KeyVaultProperties>();

            foreach (Vault curVault in vaultsRetrieved)
            {
                keyVaultsRetrieved.Add(new KeyVaultProperties(curVault, graphClient));
            }
            log.Info("Vaults retrieved!");
            return(keyVaultsRetrieved);
        }
예제 #9
0
        /// <summary>
        /// This method verifies that the Contributor permission has been granted on sufficient scopes to retrieve the key vaults.
        /// </summary>
        /// <param name="vaultList">The data obtained from deserializing json file</param>
        /// <param name="azureClient">The IAzure client used to access role assignments</param>
        public void checkAccess(JsonInput vaultList, Microsoft.Azure.Management.Fluent.Azure.IAuthenticated azureClient)
        {
            log.Info("Verifying access to Vaults...");
            List <string>    accessNeeded  = new List <string>();
            IRoleAssignments accessControl = azureClient.RoleAssignments;

            foreach (Resource res in vaultList.Resources)
            {
                try
                {
                    string subsPath        = Constants.SUBS_PATH + res.SubscriptionId;
                    var    roleAssignments = accessControl.ListByScope(subsPath).ToLookup(r => r.Inner.Scope);

                    var subsAccess = roleAssignments[subsPath].Count();
                    if (subsAccess == 0)
                    {
                        // At Subscription scope
                        if (res.ResourceGroups.Count == 0)
                        {
                            accessNeeded.Add(subsPath);
                        }
                        else
                        {
                            foreach (ResourceGroup resGroup in res.ResourceGroups)
                            {
                                string resGroupPath   = subsPath + Constants.RESGROUP_PATH + resGroup.ResourceGroupName;
                                var    resGroupAccess = roleAssignments[resGroupPath].Count();
                                if (resGroupAccess == 0)
                                {
                                    // At ResourceGroup scope
                                    if (resGroup.KeyVaults.Count == 0)
                                    {
                                        accessNeeded.Add(subsPath);
                                    }
                                    else
                                    {
                                        // At Vault scope
                                        foreach (string vaultName in resGroup.KeyVaults)
                                        {
                                            string vaultPath   = resGroupPath + Constants.VAULT_PATH + vaultName;
                                            var    vaultAccess = roleAssignments[vaultPath].Count();
                                            if (vaultAccess == 0)
                                            {
                                                accessNeeded.Add(vaultPath);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (CloudException e)
                {
                    log.Error("SubscriptionNotFound");
                    log.Debug($"{e.Message}. Please verify that your SubscriptionId is valid.");
                    Exit(e.Message);
                }
            }

            if (accessNeeded.Count() != 0)
            {
                log.Error("AuthorizationFail");
                log.Debug($"Contributor access is needed on the following scope(s): \n{string.Join("\n", accessNeeded)}. \nEnsure that your ResourceGroup and KeyVault names are spelled correctly " +
                          $"before proceeding. Note that if you are retrieving specific KeyVaults, your AAD must be granted access at either the KeyVault, ResourceGroup, Subscription level. " +
                          $"If you are retrieving all of the KeyVaults from a ResourceGroup, your AAD must be granted access at either the ResourceGroup or Subscription level. " +
                          $"If you are retrieving all of the KeyVaults from a SubscriptionId, your AAD must be granted access at the Subscription level. " +
                          $"Refer to the 'Granting Access to the AAD Application' section for more information on granting this access: https://github.com/microsoft/Managing-RBAC-in-Azure/blob/master/README.md");
                Exit($"Contributor access is needed on the following scope(s): \n{string.Join("\n", accessNeeded)}");
            }
            log.Info("Access verified!");
        }