Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add acl config #83

Merged
merged 1 commit into from
Apr 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 37 additions & 19 deletions ansible_deployer/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,20 +181,20 @@ def load_configuration_file(config_path: str):
try:
config = yaml.safe_load(config_stream)
except yaml.YAMLError as e:
logger.critical(e)
logger.critical("Yaml loading failed for %s due to %s.", config_path, e)
sys.exit(51)

with open(os.path.join(conf["global_paths"]["config_dir"], "schema", config_file), "r",
encoding="utf8") as schema_stream:
schema_path = os.path.join(conf["global_paths"]["config_dir"], "schema", config_file)
with open(schema_path, "r", encoding="utf8") as schema_stream:
try:
schema = yaml.safe_load(schema_stream)
except yaml.YAMLError as e:
logger.critical(e)
logger.critical("Yaml loading failed for %s due to %s.", config_path, e)
sys.exit(52)

validator = Validator(schema)
if not validator.validate(config, schema):
logger.critical(validator.errors)
logger.critical("Yaml validation failed for %s due to %s.", config_path, validator.errors)
sys.exit(53)

logger.debug("Loaded:\n%s", str(config))
Expand Down Expand Up @@ -222,6 +222,7 @@ def get_config_paths():
yamls = []
infra_cfg = None
tasks_cfg = None
acl_cfg = None

for config in os.listdir(conf["global_paths"]["config_dir"]):
if config != "ansible-deploy.yaml":
Expand All @@ -234,6 +235,8 @@ def get_config_paths():
infra_cfg = os.path.join(conf["global_paths"]["config_dir"], config)
elif config.startswith("tasks"):
tasks_cfg = os.path.join(conf["global_paths"]["config_dir"], config)
elif config.startswith("acl"):
acl_cfg = os.path.join(conf["global_paths"]["config_dir"], config)

if len(ymls) > 0 and len(yamls) > 0:
logger.debug("Config files with yml extensions: %s", " ".join(ymls))
Expand All @@ -252,23 +255,35 @@ def get_config_paths():
conf["global_paths"]["config_dir"])
sys.exit(44)

return infra_cfg, tasks_cfg
if not acl_cfg:
logger.critical("Permission configuration file does not exist in %s!",
conf["global_paths"]["config_dir"])
sys.exit(45)

return infra_cfg, tasks_cfg, acl_cfg

def load_configuration():
"""Function responsible for reading configuration files and running a schema validator against
it
"""
logger.debug("load_configuration called")
#TODO: validate files/directories permissions - should be own end editable only by special user
infra_cfg, tasks_cfg = get_config_paths()
infra_cfg, tasks_cfg, acl_cfg = get_config_paths()

infra = load_configuration_file(infra_cfg)
tasks = load_configuration_file(tasks_cfg)
acl = load_configuration_file(acl_cfg)

config = {}
config["infra"] = infra["infrastructures"]
config["tasks"] = tasks

config["acl"] = {}
for group in acl["acl_lists"]:
key = group["name"]
group.pop("name")
config["acl"][key] = group

return config

def validate_option_by_dict_with_name(optval: str, conf: dict):
Expand Down Expand Up @@ -554,27 +569,30 @@ def run_playitem(config: dict, options: dict, inventory: str, lockpath: str):
sys.exit(errno.ENOENT)


def verify_task_permissions(selected_items, user_groups):
def verify_task_permissions(selected_items: dict, user_groups: list, config: dict):
"""
Function verifies if the running user is allowed to run the task
"""
s_task = selected_items["task"]
s_infra = selected_items["infra"]
o_stage = selected_items["stage"]
logger.debug("Running verify_task_permissions, for s_task:%s, s_infra:%s, o_stage:%s and user"
"groups: %s", s_task, s_infra, o_stage, user_groups)

for allow_group in s_task["allowed_for"]:
logger.debug("\tChecking group: %s, for user_groups:%s", allow_group, user_groups)
if allow_group["group"] in user_groups:
for infra in allow_group["infra"]:
logger.debug("\t\tChecking infra: %s for infra:%s", infra,
logger.debug("Running verify_task_permissions for s_task:\n%s,\ns_infra:\n%s,\no_stage:\n%s\n"
"and user groups:\n%s", s_task, s_infra, o_stage, user_groups)

for item in s_task["allowed_for"]:
acl_group = item["acl_group"]
logger.debug("\tChecking permission group: %s, for user_groups: %s", acl_group, user_groups)
logger.debug("\tPermission group %s content: %s", acl_group, str(config["acl"][acl_group]))
if config["acl"][acl_group]["group"] in user_groups:
for infra in config["acl"][acl_group]["infra"]:
logger.debug("\t\tChecking infra: %s for infra: %s", infra,
selected_items["infra"]["name"])
if infra["name"] == selected_items["infra"]["name"]:
for stage in infra["stages"]:
logger.debug("\t\t\tChecking stage:%s for stage:%s", stage, o_stage["name"])
logger.debug("\t\t\tChecking stage: %s for stage: %s", stage,
o_stage["name"])
if stage == o_stage["name"]:
logger.debug("Task allowed, based on %s", allow_group)
logger.debug("Task allowed, based on %s", acl_group)
return True
logger.debug("Task forbidden")
return False
Expand Down Expand Up @@ -674,7 +692,7 @@ def main():
inv_file = get_inventory_file(config, options)
lockpath = os.path.join(lockdir, inv_file.lstrip(f".{os.sep}").replace(os.sep, "_"))
if options["subcommand"] in ("run", "verify"):
if not verify_task_permissions(selected_items, user_groups):
if not verify_task_permissions(selected_items, user_groups, config):
logger.critical("Task forbidden")
sys.exit(errno.EPERM)
setup_ansible(config["tasks"]["setup_hooks"], options["commit"], workdir)
Expand Down
68 changes: 68 additions & 0 deletions etc/acl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
acl_lists:
- name: root_on_all_in_all
group: root
infra:
- name: testInfra
stages:
- testing
- prod
- locked
- name: testInfra2
stages:
- testing
- prod
- locked
- name: testInfra3
stages:
- testing
- prod
- locked

- name: root_on_all_in_testInfra
group: root
infra:
- name: testInfra
stages:
- testing
- prod
- locked

- name: test_on_testing_in_testInfra
group: test_group
infra:
- name: testInfra
stages:
- testing

- name: root_on_testing_in_testInfra
group: root
infra:
- name: testInfra
stages:
- testing

- name: root_on_testing_in_testInfra_testInfra2
group: root
infra:
- name: testInfra
stages:
- testing
- name: testInfra2
stages:
- testing

- name: root_mixed_0001
group: root
infra:
- name: testInfra
stages:
- testing
- prod
- name: testInfra2
stages:
- testing
- name: testInfra3
stages:
- testing
- prod

23 changes: 23 additions & 0 deletions etc/schema/acl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
acl_lists:
type: list
schema:
type: dict
schema:
name:
type: string
required: True
group:
type: string
required: True
infra:
type: list
schema:
type: dict
schema:
name:
type: string
required: True
stages:
type: list
required: True

14 changes: 1 addition & 13 deletions etc/schema/tasks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,9 @@ tasks:
type: dict
required: True
schema:
group:
acl_group:
type: string
infra:
type: list
required: True
schema:
type: dict
required: True
schema:
name:
type: string
required: True
stages:
type: list
required: True
commit:
type: list
required: False
Expand Down
Loading