diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 3ddc5bd69b0481ebce098460afa9e23c6af48de4..62564979b502b847057c9f89c06f338dfa9f6da0 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -31,3 +31,8 @@ jobs:
 
       - name: Run Python linters
         uses: rjeffman/python-lint-action@v2
+
+      - name: Run pylint
+        run: |
+            pip install pylint==2.8.2
+            pylint plugins --disable=import-error
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ec90f12ae253e171bb468d3470ecfee9640c456a..24404caa208dbe4f6ef7e460ece7c9db2816d279 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,6 +21,13 @@ repos:
   rev: 5.1.1
   hooks:
   - id: pydocstyle
+- repo: https://github.com/pycqa/pylint
+  rev: v2.8.2
+  hooks:
+  - id: pylint
+    args:
+    - --disable=import-error
+    files: \.py$
 - repo: local
   hooks:
   - id: ansible-doc-test
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
index 6ce9749e8ff4941f43847645fda4345769a04e43..71ce406329ad9a28ade396a3708c3f7ceb760a76 100644
--- a/plugins/module_utils/ansible_freeipa_module.py
+++ b/plugins/module_utils/ansible_freeipa_module.py
@@ -57,7 +57,7 @@ else:
         # FreeIPA releases.
         import re
 
-        class version:
+        class version:  # pylint: disable=invalid-name, too-few-public-methods
             @staticmethod
             def parse(version_str):
                 """
@@ -65,7 +65,7 @@ else:
 
                 This will not work for `rc`, `dev` or similar version string.
                 """
-                return tuple(re.split("[-_\.]", version_str))  # noqa: W605
+                return tuple(re.split("[-_.]", version_str))  # noqa: W605
 
     from ipalib import api
     from ipalib import errors as ipalib_errors  # noqa
@@ -202,11 +202,11 @@ else:
         if not backend.isconnected():
             backend.connect(ccache=os.environ.get('KRB5CCNAME', None))
 
-    def api_command(module, command, name, args):
+    def api_command(_module, command, name, args):
         """Call ipa.Command."""
         return api.Command[command](name, **args)
 
-    def api_command_no_name(module, command, args):
+    def api_command_no_name(_module, command, args):
         """Call ipa.Command without a name."""
         return api.Command[command](**args)
 
@@ -233,7 +233,7 @@ else:
             "!=": operator.ne,
         }
         operation = oper_map.get(oper)
-        if not(operation):
+        if not operation:
             raise NotImplementedError("Invalid operator: %s" % oper)
         return operation(version.parse(VERSION),
                          version.parse(requested_version))
@@ -258,6 +258,8 @@ else:
 
         finally:
             temp_kdestroy(ccache_dir, ccache_name)
+        # fix pylint inconsistent return
+        return None
 
     def date_format(value):
         accepted_date_formats = [
@@ -269,9 +271,9 @@ else:
             '%Y-%m-%d %H:%MZ',     # non-ISO 8601, minute precision
         ]
 
-        for date_format in accepted_date_formats:
+        for _date_format in accepted_date_formats:
             try:
-                return datetime.strptime(value, date_format)
+                return datetime.strptime(value, _date_format)
             except ValueError:
                 pass
         raise ValueError("Invalid date '%s'" % value)
@@ -292,16 +294,8 @@ else:
         # If both args and ipa are None, return there's no difference.
         # If only one is None, return there is a difference.
         # This tests avoid unecessary invalid access to attributes.
-        if args is None and ipa is None:
-            return True
         if args is None or ipa is None:
-            module.debug(
-                base_debug_msg + "args is%s None an ipa is%s None" % (
-                    "" if args is None else " not",
-                    "" if ipa is None else " not",
-                )
-            )
-            return False
+            return args is None and ipa is None
 
         # Fail if args or ipa are not dicts.
         if not (isinstance(args, dict) and isinstance(ipa, dict)):
@@ -313,7 +307,7 @@ else:
         filtered_args = [key for key in args if key not in ignore]
 
         for key in filtered_args:
-            if key not in ipa:
+            if key not in ipa:  # pylint: disable=no-else-return
                 module.debug(
                     base_debug_msg + "Command key not present in IPA: %s" % key
                 )
@@ -365,15 +359,13 @@ else:
         if value is not None:
             if isinstance(value, list):
                 return [_afm_convert(x) for x in value]
-            elif isinstance(value, dict):
+            if isinstance(value, dict):
                 return {_afm_convert(k): _afm_convert(v)
                         for k, v in value.items()}
-            elif isinstance(value, str):
+            if isinstance(value, str):
                 return to_text(value)
-            else:
-                return value
-        else:
-            return value
+
+        return value
 
     def module_params_get(module, name):
         return _afm_convert(module.params.get(name))
@@ -460,14 +452,13 @@ else:
             cert = load_certificate(cert.encode('utf-8'))
         return cert
 
-    def DN_x500_text(text):
+    def DN_x500_text(text):  # pylint: disable=invalid-name
         if hasattr(DN, "x500_text"):
             return DN(text).x500_text()
-        else:
-            # Emulate x500_text
-            dn = DN(text)
-            dn.rdns = reversed(dn.rdns)
-            return str(dn)
+        # Emulate x500_text
+        dn = DN(text)
+        dn.rdns = reversed(dn.rdns)
+        return str(dn)
 
     def is_valid_port(port):
         if not isinstance(port, int):
@@ -536,8 +527,9 @@ else:
 
         def __getitem__(self, key):
             param = self.mapping[key]
-            if param is not None:
-                return _afm_convert(param)
+            if param is None:
+                return None
+            return _afm_convert(param)
 
         def __iter__(self):
             return iter(self.mapping)
@@ -622,6 +614,7 @@ else:
         ipa_param_mapping = None
 
         def __init__(self, *args, **kwargs):
+            # pylint: disable=super-with-arguments
             super(FreeIPABaseModule, self).__init__(*args, **kwargs)
 
             # Attributes to store kerberos credentials (if needed)
@@ -700,7 +693,7 @@ else:
 
         def check_ipa_params(self):
             """Validate ipa_params before command is called."""
-            pass
+            pass  # pylint: disable=unnecessary-pass
 
         def define_ipa_commands(self):
             """Define commands that will be run in IPA server."""
@@ -785,7 +778,7 @@ else:
                         )
 
             if len(errors) > 0:
-                self.fail_json(", ".join("errors"))
+                self.fail_json(", ".join("errors"))  # pylint: disable=E1121
 
         def add_ipa_command(self, command, name=None, args=None):
             """Add a command to the list of commands to be executed."""
@@ -805,7 +798,7 @@ else:
                     self.process_command_result(name, command, args, result)
                 self.get_command_errors(command, result)
 
-        def process_command_result(self, name, command, args, result):
+        def process_command_result(self, _name, _command, _args, result):
             """
             Process an API command result.
 
diff --git a/plugins/modules/ipaconfig.py b/plugins/modules/ipaconfig.py
index e97e364785dd0a4c61fa0a7e23253dc02ea4c109..dad9bd9df45d665aea6b6766417ec03573aa16fd 100644
--- a/plugins/modules/ipaconfig.py
+++ b/plugins/modules/ipaconfig.py
@@ -264,10 +264,7 @@ def config_show(module):
 
 
 def gen_args(params):
-    _args = {}
-    for k, v in params.items():
-        if v is not None:
-            _args[k] = v
+    _args = {k: v for k, v in params.items() if v is not None}
 
     return _args
 
@@ -368,7 +365,7 @@ def main():
     reverse_field_map = {v: k for k, v in field_map.items()}
 
     params = {}
-    for x in field_map.keys():
+    for x in field_map:
         val = module_params_get(ansible_module, x)
 
         if val is not None:
@@ -402,11 +399,11 @@ def main():
         ("ipasearchrecordslimit", -1, 2147483647),
         ("ipapwdexpadvnotify", 0, 2147483647),
     ]
-    for arg, min, max in args_with_limits:
-        if arg in params and (params[arg] > max or params[arg] < min):
+    for arg, minimum, maximum in args_with_limits:
+        if arg in params and (params[arg] > maximum or params[arg] < minimum):
             ansible_module.fail_json(
                 msg="Argument '%s' must be between %d and %d."
-                    % (arg, min, max))
+                    % (arg, minimum, maximum))
 
     changed = False
     exit_args = {}
@@ -434,7 +431,7 @@ def main():
             rawresult = api_command_no_name(ansible_module, "config_show", {})
             result = rawresult['result']
             del result['dn']
-            for key, v in result.items():
+            for key, value in result.items():
                 k = reverse_field_map.get(key, key)
                 if ansible_module.argument_spec.get(k):
                     if k == 'ipaselinuxusermaporder':
@@ -449,20 +446,20 @@ def main():
                     elif k == 'groupsearch':
                         exit_args['groupsearch'] = \
                             result.get(key)[0].split(',')
-                    elif isinstance(v, str) and \
+                    elif isinstance(value, str) and \
                             ansible_module.argument_spec[k]['type'] == "list":
-                        exit_args[k] = [v]
-                    elif isinstance(v, list) and \
+                        exit_args[k] = [value]
+                    elif isinstance(value, list) and \
                             ansible_module.argument_spec[k]['type'] == "str":
-                        exit_args[k] = ",".join(v)
-                    elif isinstance(v, list) and \
+                        exit_args[k] = ",".join(value)
+                    elif isinstance(value, list) and \
                             ansible_module.argument_spec[k]['type'] == "int":
-                        exit_args[k] = ",".join(v)
-                    elif isinstance(v, list) and \
+                        exit_args[k] = ",".join(value)
+                    elif isinstance(value, list) and \
                             ansible_module.argument_spec[k]['type'] == "bool":
-                        exit_args[k] = (v[0] == "TRUE")
+                        exit_args[k] = (value[0] == "TRUE")
                     else:
-                        exit_args[k] = v
+                        exit_args[k] = value
     except ipalib_errors.EmptyModlist:
         changed = False
     except Exception as e:
diff --git a/plugins/modules/ipadnsconfig.py b/plugins/modules/ipadnsconfig.py
index a0f2bc56c0454664b165296cd23e19cba3ba67c9..8d705807bc0d8ca057c7cede0153ee40e4da1bc7 100644
--- a/plugins/modules/ipadnsconfig.py
+++ b/plugins/modules/ipadnsconfig.py
@@ -114,8 +114,8 @@ def find_dnsconfig(module):
         if _result["result"].get('idnsforwarders', None) is None:
             _result["result"]['idnsforwarders'] = ['']
         return _result["result"]
-    else:
-        module.fail_json(msg="Could not retrieve current DNS configuration.")
+
+    module.fail_json(msg="Could not retrieve current DNS configuration.")
     return None
 
 
diff --git a/plugins/modules/ipadnsforwardzone.py b/plugins/modules/ipadnsforwardzone.py
index ffebc3d23ed81325c8ff37172b07413f15e7bc10..1c2a22e53d84e9a0f4e4b677222a1af95e2039cb 100644
--- a/plugins/modules/ipadnsforwardzone.py
+++ b/plugins/modules/ipadnsforwardzone.py
@@ -135,8 +135,8 @@ def find_dnsforwardzone(module, name):
             msg="There is more than one dnsforwardzone '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(forwarders, forwardpolicy, skip_overlap_check):
@@ -386,8 +386,8 @@ def main():
                                          **exit_args)
 
             # Execute commands
-            for name, command, args in commands:
-                api_command(ansible_module, command, name, args)
+            for _name, command, args in commands:
+                api_command(ansible_module, command, _name, args)
                 changed = True
 
     except Exception as e:
diff --git a/plugins/modules/ipadnsrecord.py b/plugins/modules/ipadnsrecord.py
index 0b998be6f13b4b7e5d531f621def9d7ea25c6963..1741a7a74a2051d0aa439a87521ed48d3fecee88 100644
--- a/plugins/modules/ipadnsrecord.py
+++ b/plugins/modules/ipadnsrecord.py
@@ -1377,7 +1377,7 @@ def define_commands_for_present_state(module, zone_name, entry, res_find):
                     _args['idnsname'] = name
                     _commands.append([zone_name, 'dnsrecord_add', _args])
                 # clean used fields from args
-                for f in part_fields:
+                for f in part_fields:   # pylint: disable=invalid-name
                     if f in args:
                         del args[f]
             else:
diff --git a/plugins/modules/ipadnszone.py b/plugins/modules/ipadnszone.py
index 8500eb1497c26c41b3834f989eb7283e495787d4..ae8ed93ad5da2172123df2f194b4347db9d2c520 100644
--- a/plugins/modules/ipadnszone.py
+++ b/plugins/modules/ipadnszone.py
@@ -263,22 +263,18 @@ class DNSZoneModule(FreeIPABaseModule):
         if any(invalid_ips):
             self.fail_json(msg=error_msg % invalid_ips)
 
-    def is_valid_nsec3param_rec(self, nsec3param_rec):
+    def is_valid_nsec3param_rec(self, nsec3param_rec):  # pylint: disable=R0201
         try:
             part1, part2, part3, part4 = nsec3param_rec.split(" ")
         except ValueError:
             return False
 
-        if not all([part1.isdigit(), part2.isdigit(), part3.isdigit()]):
-            return False
-
-        if not 0 <= int(part1) <= 255:
-            return False
-
-        if not 0 <= int(part2) <= 255:
-            return False
-
-        if not 0 <= int(part3) <= 65535:
+        if (
+            not all([part1.isdigit(), part2.isdigit(), part3.isdigit()])
+            or not 0 <= int(part1) <= 255
+            or not 0 <= int(part2) <= 255
+            or not 0 <= int(part3) <= 65535
+        ):
             return False
 
         try:
@@ -298,7 +294,7 @@ class DNSZoneModule(FreeIPABaseModule):
 
         return True
 
-    def get_ipa_nsec3paramrecord(self, **kwargs):
+    def get_ipa_nsec3paramrecord(self, **_kwargs):  # pylint: disable=R1710
         nsec3param_rec = self.ipa_params.nsec3param_rec
         if nsec3param_rec is not None:
             error_msg = (
@@ -310,12 +306,12 @@ class DNSZoneModule(FreeIPABaseModule):
                 self.fail_json(msg=error_msg)
             return nsec3param_rec
 
-    def get_ipa_idnsforwarders(self, **kwargs):
+    def get_ipa_idnsforwarders(self, **_kwargs):  # pylint: disable=R1710
         if self.ipa_params.forwarders is not None:
             forwarders = []
             for forwarder in self.ipa_params.forwarders:
                 ip_address = forwarder.get("ip_address")
-                if not (is_ip_address(ip_address)):
+                if not is_ip_address(ip_address):
                     self.fail_json(
                         msg="Invalid IP for DNS forwarder: %s" % ip_address
                     )
@@ -334,14 +330,14 @@ class DNSZoneModule(FreeIPABaseModule):
 
             return forwarders
 
-    def get_ipa_idnsallowtransfer(self, **kwargs):
+    def get_ipa_idnsallowtransfer(self, **_kwargs):  # pylint: disable=R1710
         if self.ipa_params.allow_transfer is not None:
             error_msg = "Invalid ip_address for DNS allow_transfer: %s"
             self.validate_ips(self.ipa_params.allow_transfer, error_msg)
 
             return (";".join(self.ipa_params.allow_transfer) or "none") + ";"
 
-    def get_ipa_idnsallowquery(self, **kwargs):
+    def get_ipa_idnsallowquery(self, **_kwargs):  # pylint: disable=R1710
         if self.ipa_params.allow_query is not None:
             error_msg = "Invalid ip_address for DNS allow_query: %s"
             self.validate_ips(self.ipa_params.allow_query, error_msg)
@@ -364,27 +360,27 @@ class DNSZoneModule(FreeIPABaseModule):
 
         return ".".join((name, domain))
 
-    def get_ipa_idnssoarname(self, **kwargs):
+    def get_ipa_idnssoarname(self, **_kwargs):  # pylint: disable=R1710
         if self.ipa_params.admin_email is not None:
             return DNSName(
                 self._replace_at_symbol_in_rname(self.ipa_params.admin_email)
             )
 
-    def get_ipa_idnssoamname(self, **kwargs):
+    def get_ipa_idnssoamname(self, **_kwargs):  # pylint: disable=R1710
         if self.ipa_params.name_server is not None:
             return DNSName(self.ipa_params.name_server)
 
-    def get_ipa_skip_overlap_check(self, **kwargs):
+    def get_ipa_skip_overlap_check(self, **kwargs):  # pylint: disable=R1710
         zone = kwargs.get('zone')
         if not zone and self.ipa_params.skip_overlap_check is not None:
             return self.ipa_params.skip_overlap_check
 
-    def get_ipa_skip_nameserver_check(self, **kwargs):
+    def get_ipa_skip_nameserver_check(self, **kwargs):  # pylint: disable=R1710
         zone = kwargs.get('zone')
         if not zone and self.ipa_params.skip_nameserver_check is not None:
             return self.ipa_params.skip_nameserver_check
 
-    def __reverse_zone_name(self, ipaddress):
+    def __reverse_zone_name(self, ipaddress):  # pylint: disable=R1710
         """
         Infer reverse zone name from an ip address.
 
@@ -404,10 +400,9 @@ class DNSZoneModule(FreeIPABaseModule):
             ip_version = ip.version
         if ip_version == 4:
             return u'.'.join(items[4 - prefixlen // 8:])
-        elif ip_version == 6:
+        if ip_version == 6:
             return u'.'.join(items[32 - prefixlen // 4:])
-        else:
-            self.fail_json(msg="Invalid IP version for reverse zone.")
+        self.fail_json(msg="Invalid IP version for reverse zone.")
 
     def get_zone(self, zone_name):
         get_zone_args = {"idnsname": zone_name, "all": True}
@@ -505,6 +500,7 @@ class DNSZoneModule(FreeIPABaseModule):
                 self.add_ipa_command("dnszone_mod", zone_name, args)
 
     def process_command_result(self, name, command, args, result):
+        # pylint: disable=super-with-arguments
         super(DNSZoneModule, self).process_command_result(
             name, command, args, result
         )
diff --git a/plugins/modules/ipagroup.py b/plugins/modules/ipagroup.py
index e7072f08adb20b71e6a4fa0655cf3aa86fb3188d..bfddebf451d20e0da89ca457e62f0e81f4d68b92 100644
--- a/plugins/modules/ipagroup.py
+++ b/plugins/modules/ipagroup.py
@@ -201,8 +201,8 @@ def find_group(module, name):
             msg="There is more than one group '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description, gid, nomembers):
diff --git a/plugins/modules/ipahbacrule.py b/plugins/modules/ipahbacrule.py
index 12fad26ce2e573c5b797bef886e1985f28dc13a5..010f68a9a44914f0ffb01e43fdf296e7a162705e 100644
--- a/plugins/modules/ipahbacrule.py
+++ b/plugins/modules/ipahbacrule.py
@@ -175,8 +175,8 @@ def find_hbacrule(module, name):
             msg="There is more than one hbacrule '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description, usercategory, hostcategory, servicecategory,
diff --git a/plugins/modules/ipahbacsvc.py b/plugins/modules/ipahbacsvc.py
index 1ead6d53d66b1cef19f69d137a5c334fb228c8fa..26e6a95752668f84cc2c1692f62fdd39d31c6187 100644
--- a/plugins/modules/ipahbacsvc.py
+++ b/plugins/modules/ipahbacsvc.py
@@ -89,8 +89,8 @@ def find_hbacsvc(module, name):
             msg="There is more than one hbacsvc '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description):
diff --git a/plugins/modules/ipahbacsvcgroup.py b/plugins/modules/ipahbacsvcgroup.py
index 6676bca71b8b551b953e77e5c7702beb37131b5b..141fa5391448d93dede6dd74a5a5e817447574f9 100644
--- a/plugins/modules/ipahbacsvcgroup.py
+++ b/plugins/modules/ipahbacsvcgroup.py
@@ -121,8 +121,8 @@ def find_hbacsvcgroup(module, name):
             msg="There is more than one hbacsvcgroup '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description, nomembers):
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
index 4bf7c47cf943d6e0d61e1622d3f9acc0510c2003..0bd5b1b426b74b7a638b9f27abbc07a5587b5ef5 100644
--- a/plugins/modules/ipahost.py
+++ b/plugins/modules/ipahost.py
@@ -466,7 +466,7 @@ def show_host(module, name):
 
 def gen_args(description, locality, location, platform, os, password, random,
              mac_address, sshpubkey, userclass, auth_ind, requires_pre_auth,
-             ok_as_delegate, ok_to_auth_as_delegate, force, reverse,
+             ok_as_delegate, ok_to_auth_as_delegate, force, _reverse,
              ip_address, update_dns):
     # certificate, managedby_host, principal, create_keytab_* and
     # allow_retrieve_keytab_* are not handled here
@@ -529,7 +529,7 @@ def gen_dnsrecord_args(module, ip_address, reverse):
     return _args
 
 
-def check_parameters(
+def check_parameters(   # pylint: disable=unused-argument
         module, state, action,
         description, locality, location, platform, os, password, random,
         certificate, managedby_host, principal, allow_create_keytab_user,
@@ -862,7 +862,7 @@ def main():
                     ok_to_auth_as_delegate, force, reverse, ip_address,
                     update_dns, update_password)
 
-            elif isinstance(host, str) or isinstance(host, unicode):
+            elif isinstance(host, (str, unicode)):
                 name = host
             else:
                 ansible_module.fail_json(msg="Host '%s' is not valid" %
diff --git a/plugins/modules/ipahostgroup.py b/plugins/modules/ipahostgroup.py
index 8c594353c275ed48b2c11dc8e2b54a53472115cb..ff13cc59777e86fdbb6c825347e20e0f2bb53014 100644
--- a/plugins/modules/ipahostgroup.py
+++ b/plugins/modules/ipahostgroup.py
@@ -157,8 +157,8 @@ def find_hostgroup(module, name):
             msg="There is more than one hostgroup '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description, nomembers, rename):
diff --git a/plugins/modules/ipapwpolicy.py b/plugins/modules/ipapwpolicy.py
index 77fa023d90d327e80432606a278d8d3552883905..c9509f4ddf4f16d5863d90427771376e6c9be7cd 100644
--- a/plugins/modules/ipapwpolicy.py
+++ b/plugins/modules/ipapwpolicy.py
@@ -130,8 +130,8 @@ def find_pwpolicy(module, name):
             msg="There is more than one pwpolicy '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(maxlife, minlife, history, minclasses, minlength, priority,
diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py
index 77b934c123ad005f869d25d66ea993d61bb25889..50081be5340492e24e6e157d9920d642b33085e2 100644
--- a/plugins/modules/ipaservice.py
+++ b/plugins/modules/ipaservice.py
@@ -250,8 +250,8 @@ def find_service(module, name):
             _res["usercertificate"] = [encode_certificate(cert) for
                                        cert in certs]
         return _res
-    else:
-        return None
+
+    return None
 
 
 def gen_args(pac_type, auth_ind, skip_host_check, force, requires_pre_auth,
@@ -771,7 +771,7 @@ def main():
             elif state == "absent":
                 if action == "service":
                     if res_find is not None:
-                        args = {'continue': True if delete_continue else False}
+                        args = {'continue': delete_continue}
                         commands.append([name, 'service_del', args])
 
                 elif action == "member":
diff --git a/plugins/modules/ipasudocmd.py b/plugins/modules/ipasudocmd.py
index ca484ba97798fc67d684774d22fce535b741b84b..08344f41b6a6a351232726efe3dcfaaf27444b24 100644
--- a/plugins/modules/ipasudocmd.py
+++ b/plugins/modules/ipasudocmd.py
@@ -90,8 +90,8 @@ def find_sudocmd(module, name):
             msg="There is more than one sudocmd '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description):
diff --git a/plugins/modules/ipasudorule.py b/plugins/modules/ipasudorule.py
index 47735480cf94b6ca378934f105e91600eb30c1e5..332423f44bcdb88bb0b27dfda05d4a5d1c0efe4f 100644
--- a/plugins/modules/ipasudorule.py
+++ b/plugins/modules/ipasudorule.py
@@ -206,8 +206,8 @@ def find_sudorule(module, name):
             msg="There is more than one sudorule '%s'" % (name))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def gen_args(description, usercat, hostcat, cmdcat, runasusercat,
diff --git a/plugins/modules/ipatopologysegment.py b/plugins/modules/ipatopologysegment.py
index 4d522bdafb0b784ab0e831a5c0e3ab9b08c1225c..d29090251daddcfe5e095cef3e8b32fbca8c4eb9 100644
--- a/plugins/modules/ipatopologysegment.py
+++ b/plugins/modules/ipatopologysegment.py
@@ -132,8 +132,8 @@ def find_left_right(module, suffix, left, right):
             "not unique for suffix '%s'" % (left, right, suffix))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def find_cn(module, suffix, name):
@@ -147,8 +147,8 @@ def find_cn(module, suffix, name):
             msg="CN '%s' is not unique for suffix '%s'" % (name, suffix))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def find_left_right_cn(module, suffix, left, right, name):
diff --git a/plugins/modules/ipatrust.py b/plugins/modules/ipatrust.py
index c48dcb410569d41e5c46ab32da1b77b66b993a2a..3c14077b3390b39f8b5b3a7d65d7d52fd7a909f4 100644
--- a/plugins/modules/ipatrust.py
+++ b/plugins/modules/ipatrust.py
@@ -125,8 +125,8 @@ def find_trust(module, realm):
         module.fail_json(msg="There is more than one realm '%s'" % (realm))
     elif len(_result["result"]) == 1:
         return _result["result"][0]
-    else:
-        return None
+
+    return None
 
 
 def del_trust(module, realm):
@@ -136,8 +136,6 @@ def del_trust(module, realm):
     if len(_result["result"]["failed"]) > 0:
         module.fail_json(
             msg="Trust deletion has failed for '%s'" % (realm))
-    else:
-        return None
 
 
 def add_trust(module, realm, args):
@@ -148,12 +146,10 @@ def add_trust(module, realm, args):
     if "cn" not in _result["result"]:
         module.fail_json(
             msg="Trust add has failed for '%s'" % (realm))
-    else:
-        return None
 
 
 def gen_args(trust_type, admin, password, server, trust_secret, base_id,
-             range_size, range_type, two_way, external):
+             range_size, _range_type, two_way, external):
     _args = {}
     if trust_type is not None:
         _args["trust_type"] = trust_type
diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py
index 52463abb6f02abe366d8416c1a52545c7f89dab1..0a104cb938baa8344bda389247a0d038a2b2bc34 100644
--- a/plugins/modules/ipauser.py
+++ b/plugins/modules/ipauser.py
@@ -512,10 +512,9 @@ def find_user(module, name, preserved=False):
         if certs is not None:
             _result["usercertificate"] = [encode_certificate(x)
                                           for x in certs]
-
         return _result
-    else:
-        return None
+
+    return None
 
 
 def gen_args(first, last, fullname, displayname, initials, homedir, shell,
@@ -599,17 +598,14 @@ def gen_args(first, last, fullname, displayname, initials, homedir, shell,
     return _args
 
 
-def check_parameters(module, state, action,
-                     first, last, fullname, displayname, initials, homedir,
-                     shell, email, principal, principalexpiration,
-                     passwordexpiration, password, random, uid, gid, city,
-                     phone, mobile, pager, fax, orgunit, title, manager,
-                     carlicense, sshpubkey, userauthtype, userclass, radius,
-                     radiususer, departmentnumber, employeenumber,
-                     employeetype, preferredlanguage, certificate,
-                     certmapdata, noprivate, nomembers, preserve,
-                     update_password):
-
+def check_parameters(  # pylint: disable=unused-argument
+        module, state, action, first, last, fullname, displayname, initials,
+        homedir, shell, email, principal, principalexpiration,
+        passwordexpiration, password, random, uid, gid, city, phone, mobile,
+        pager, fax, orgunit, title, manager, carlicense, sshpubkey,
+        userauthtype, userclass, radius, radiususer, departmentnumber,
+        employeenumber, employeetype, preferredlanguage, certificate,
+        certmapdata, noprivate, nomembers, preserve, update_password):
     if state == "present":
         if action == "member":
             invalid = ["first", "last", "fullname", "displayname", "initials",
@@ -715,7 +711,7 @@ def check_certmapdata(data):
         return False
 
     i = data.find("<I>", 4)
-    s = data.find("<S>", i)
+    s = data.find("<S>", i)   # pylint: disable=invalid-name
     issuer = data[i+3:s]
     subject = data[s+3:]
 
@@ -1033,7 +1029,7 @@ def main():
 
                 email = extend_emails(email, default_email_domain)
 
-            elif isinstance(user, str) or isinstance(user, unicode):
+            elif isinstance(user, (str, unicode)):
                 name = user
             else:
                 ansible_module.fail_json(msg="User '%s' is not valid" %
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
index 1a4efb4b96b085af135a03aef3c92413642ca4de..df4bdf28c61e56081dcc21f5f5f7ffc4e52390bc 100644
--- a/plugins/modules/ipavault.py
+++ b/plugins/modules/ipavault.py
@@ -348,9 +348,9 @@ def find_vault(module, name, username, service, shared):
     return None
 
 
-def gen_args(description, username, service, shared, vault_type, salt,
-             password, password_file, public_key, public_key_file, vault_data,
-             datafile_in, datafile_out):
+def gen_args(
+        description, username, service, shared, vault_type, salt,
+        public_key, public_key_file):
     _args = {}
     vault_type = vault_type or to_text("symmetric")
 
@@ -443,12 +443,12 @@ def data_storage_args(vault_type, args, data, password, password_file,
     return _args
 
 
-def check_parameters(module, state, action, description, username, service,
-                     shared, users, groups, services, owners, ownergroups,
-                     ownerservices, vault_type, salt, password, password_file,
-                     public_key, public_key_file, private_key,
-                     private_key_file, vault_data, datafile_in, datafile_out,
-                     new_password, new_password_file):
+def check_parameters(  # pylint: disable=unused-argument
+        module, state, action, description, username, service, shared, users,
+        groups, services, owners, ownergroups, ownerservices, vault_type, salt,
+        password, password_file, public_key, public_key_file, private_key,
+        private_key_file, vault_data, datafile_in, datafile_out, new_password,
+        new_password_file):
     invalid = []
     if state == "present":
         invalid = ['datafile_out']
@@ -491,11 +491,11 @@ def check_parameters(module, state, action, description, username, service,
                     "action '%s'" % (arg, state, action))
 
 
-def check_encryption_params(module, state, action, vault_type, salt,
-                            password, password_file, public_key,
-                            public_key_file, private_key, private_key_file,
-                            vault_data, datafile_in, datafile_out,
-                            new_password, new_password_file, res_find):
+def check_encryption_params(  # pylint: disable=unused-argument
+        module, state, action, vault_type, salt, password, password_file,
+        public_key, public_key_file, private_key, private_key_file, vault_data,
+        datafile_in, datafile_out, new_password, new_password_file, res_find):
+    """Check parameters used for (de)vault data encryption."""
     vault_type_invalid = []
 
     existing_type = None
@@ -757,9 +757,7 @@ def main():
 
             # Generate args
             args = gen_args(description, username, service, shared, vault_type,
-                            salt, password, password_file, public_key,
-                            public_key_file, vault_data, datafile_in,
-                            datafile_out)
+                            salt, public_key, public_key_file)
             pwdargs = None
 
             # Create command
diff --git a/setup.cfg b/setup.cfg
index 4d60e31fa33eda466101920e0db8757e259eeb95..a470e2f9fa798d73049bec4404ea6469acfeb224 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -31,3 +31,40 @@ per-file-ignores =
 [pydocstyle]
 inherit = false
 ignore = D1,D212,D203
+
+[pylint.MASTER]
+disable =
+    c-extension-no-member,
+    missing-module-docstring,
+    missing-class-docstring,
+    missing-function-docstring,
+    wrong-import-order,
+    ungrouped-imports,
+    wrong-import-position,
+    protected-access,
+    no-name-in-module,
+    too-many-arguments,
+    too-many-statements,
+    too-many-lines,
+    raise-missing-from,
+    duplicate-code,
+    broad-except,
+    too-many-branches,
+    too-many-locals,
+    fixme
+
+[pylint.BASIC]
+good-names = ex, i, j, k, Run, _, e, x, dn, cn, ip, os, unicode
+
+[pylint.IMPORTS]
+ignored-modules =
+    ansible.module_utils.ansible_freeipa_module,
+    ipalib, ipalib.config, ipalib.constants, ipalib.krb_utils, ipalib.errors,
+    ipapython.ipautil, ipapython.dn, ipapython.version, ipapython.dnsutil,
+    ipaplatform.paths
+
+[pylint.REFACTORING]
+max-nested-blocks = 9
+
+[pylint.FORMAT]
+max-line-length = 80
diff --git a/utils/lint_check.sh b/utils/lint_check.sh
index eba2c1d53ba42ee8f6d8c5371fe01316945fe6b5..d7bfadc3b53d34a1c245a9252c928e7c35282276 100755
--- a/utils/lint_check.sh
+++ b/utils/lint_check.sh
@@ -4,6 +4,7 @@ topdir="`dirname $(dirname $0)`"
 
 flake8 .
 pydocstyle .
+pylint plugins
 
 ANSIBLE_LIBRARY=${ANSIBLE_LIBRARY:-"${topdir}/plugins/modules"}
 ANSIBLE_MODULE_UTILS=${ANSIBLE_MODULE_UTILS:-"${topdir}/plugins/module_utils"}
@@ -24,5 +25,5 @@ done
 
 for dir in "${yaml_dirs[@]}"
 do
-    find "${dir}" -type f -name "*.yml" | xargs yamllint 
+    find "${dir}" -type f -name "*.yml" | xargs yamllint
 done