Merge lp:~canonical-platform-qa/qakit/appamor-utilities into lp:qakit

Proposed by Heber Parrucci
Status: Merged
Merged at revision: 200
Proposed branch: lp:~canonical-platform-qa/qakit/appamor-utilities
Merge into: lp:qakit
Diff against target: 156 lines (+146/-0)
2 files modified
qakit/apparmor/__init__.py (+18/-0)
qakit/apparmor/apparmor_utils.py (+128/-0)
To merge this branch: bzr merge lp:~canonical-platform-qa/qakit/appamor-utilities
Reviewer Review Type Date Requested Status
Santiago Baldassin (community) Approve
Review via email: mp+309374@code.launchpad.net

Commit message

adding apparmor utilities to update profiles with given rules.
update_profile: to update an apparmor profile/s
restore_profiles: to get back the original ones loaded in the system.
are_rules_present: to check if certain rules are present in a given profile.

Description of the change

Change contains utilities to update apparmor profiles with given rules.

We will need this to be able to run automated tests against snaps applications. The idea is that the tests call this in their setup before running the tests.

Utilities:
update_profile, are_rules_present, restore_profiles

To post a comment you must log in.
Revision history for this message
Santiago Baldassin (sbaldassin) wrote :

Code looks good to me

review: Approve
200. By Heber Parrucci

merge from trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'qakit/apparmor'
=== added file 'qakit/apparmor/__init__.py'
--- qakit/apparmor/__init__.py 1970-01-01 00:00:00 +0000
+++ qakit/apparmor/__init__.py 2016-10-26 18:00:51 +0000
@@ -0,0 +1,18 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Apparmor Utils
4# Copyright (C) 2016 Canonical
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
019
=== added file 'qakit/apparmor/apparmor_utils.py'
--- qakit/apparmor/apparmor_utils.py 1970-01-01 00:00:00 +0000
+++ qakit/apparmor/apparmor_utils.py 2016-10-26 18:00:51 +0000
@@ -0,0 +1,128 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Apparmor Utils
4# Copyright (C) 2016 Canonical
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19
20import os
21
22PROFILES_DIR = '/var/lib/snapd/apparmor/profiles'
23BACKUP_DIR = '/tmp/profiles_bkp'
24APPARMOR_PARSER_CMD = 'apparmor_parser -r'
25
26
27def update_profile(rules,
28 profiles=None,
29 profiles_dir=PROFILES_DIR,
30 password=None):
31 """Update apparmor's profile/s with given rules file,
32 it concatenates the rules to the original profile.
33 Before updating the profile/s it does a backup of the original
34 one so they can be restored later by calling to function:
35 restore_profiles()
36 :param rules: a string that represents the rules to add
37 :param profiles: the profile name list to add
38 the rules for.
39 If None, all the profiles will be updated.
40 If one profile already has the given rules,
41 it will not be backed-up or updated.
42 :param profiles_dir: directory path that contains apparmor profiles
43 :param password: the password to execute the commands as superuser,
44 if it is not provided,
45 it will be read from the environment variable PASSWORD,
46 if none of them are set, it will fail.
47 """
48 assert password or os.environ.get('PASSWORD'), \
49 'You either need to provide the password as ' \
50 'parameter or set the environment variable PASSWORD'
51 password = password or os.environ.get('PASSWORD')
52 found_profiles = os.listdir(profiles_dir)
53 if profiles:
54 found_profiles = [p for p in profiles if p in found_profiles]
55 __ensure_backup_dir()
56 for profile in found_profiles:
57 if not are_rules_present(rules, profile):
58 profile_full_path = os.path.join(profiles_dir, profile)
59 # backup up original profile to restore later
60 __run_with_sudo('cp %s %s' % (profile_full_path,
61 os.path.join(BACKUP_DIR,
62 profile)),
63 password)
64 original_rules = open(profile_full_path, mode='r').read()
65 with open('/tmp/%s.tmp' % profile, 'w') as temp:
66 # write to tmp file: original rules + new ones
67 temp.write(original_rules.rstrip('}\n'))
68 temp.write('\n\n')
69 temp.write(rules)
70
71 # replace original profile with the updated one
72 __run_with_sudo('mv %s %s' % ('/tmp/%s.tmp' % profile,
73 profile_full_path), password)
74 # refresh appamor profile
75 __run_with_sudo('%s %s' % (APPARMOR_PARSER_CMD,
76 profile_full_path),
77 password)
78
79
80def are_rules_present(rules, profile_name, profiles_dir=PROFILES_DIR):
81 """Check in the apparmor profile if the given rules are present
82 :param rules: a string that represents the rules to check
83 :param profiles_dir: directory path that contains apparmor profiles
84 :param profile_name: the profile name to check
85 :return True if the rules rules are present in the given profile,
86 False otherwise
87 """
88 with open(os.path.join(profiles_dir, profile_name), mode='r') as p:
89 return p.read().find(rules) > 0
90
91
92def restore_profiles(profiles=None, profiles_dir=PROFILES_DIR, password=None):
93 """Restore the already backed-up profile/s
94 If there are no profiles backed-up, it will do nothing
95 :param profiles: the profiles name list to restore.
96 If None, it will restore all the profiles present in the backup directory
97 :param profiles_dir: directory path that contains apparmor profiles
98 :param password: the password to execute the commands as superuser,
99 if it is not provided,
100 it will be read from the environment variable PASSWORD,
101 if none of them are set, it will fail.
102 """
103 assert password or os.environ.get('PASSWORD'), \
104 'You either need to provide the password as ' \
105 'parameter or set the environment variable PASSWORD'
106 password = password or os.environ.get('PASSWORD')
107 found_profiles = os.listdir(profiles_dir)
108 if profiles:
109 found_profiles = [p for p in profiles if p in found_profiles]
110 for bkp in found_profiles:
111 if bkp in os.listdir(BACKUP_DIR):
112 # restore profile
113 __run_with_sudo('mv %s %s' % (os.path.join(BACKUP_DIR, bkp),
114 os.path.join(profiles_dir, bkp)),
115 password)
116 # refresh appamor profile
117 __run_with_sudo('%s %s' % (APPARMOR_PARSER_CMD,
118 os.path.join(profiles_dir, bkp)),
119 password)
120
121
122def __ensure_backup_dir():
123 if not os.path.exists(BACKUP_DIR):
124 os.makedirs(BACKUP_DIR)
125
126
127def __run_with_sudo(command, password):
128 return os.system('echo %s|sudo -S %s 2>/dev/null' % (password, command))

Subscribers

People subscribed via source and target branches

to all changes: