diff --git a/ansible/action_plugins/merge_configs.py b/ansible/action_plugins/merge_configs.py
index 556bfa83b1f1f63df31a5c17a6765876bf4625ee..4377dd8c1ae04ea70f89fe924a305b3b9185992d 100644
--- a/ansible/action_plugins/merge_configs.py
+++ b/ansible/action_plugins/merge_configs.py
@@ -19,7 +19,10 @@
 import collections
 import inspect
 import os
+import shutil
+import tempfile
 
+from ansible import constants
 from ansible.plugins import action
 from six import StringIO
 
@@ -131,22 +134,34 @@ class ActionModule(action.ActionBase):
 
         fakefile = StringIO()
         config.write(fakefile)
-
-        remote_path = self._connection._shell.join_path(tmp, 'src')
-        xfered = self._transfer_data(remote_path, fakefile.getvalue())
+        full_source = fakefile.getvalue()
         fakefile.close()
 
-        new_module_args = self._task.args.copy()
-        new_module_args.pop('sources', None)
+        local_tempdir = tempfile.mkdtemp(dir=constants.DEFAULT_LOCAL_TMP)
+
+        try:
+            result_file = os.path.join(local_tempdir, 'source')
+            with open(result_file, 'wb') as f:
+                f.write(full_source)
+
+            new_task = self._task.copy()
+            new_task.args.pop('sources', None)
 
-        new_module_args.update(
-            dict(
-                src=xfered
+            new_task.args.update(
+                dict(
+                    src=result_file
+                )
             )
-        )
 
-        result.update(self._execute_module(module_name='copy',
-                                           module_args=new_module_args,
-                                           task_vars=task_vars,
-                                           tmp=tmp))
+            copy_action = self._shared_loader_obj.action_loader.get(
+                'copy',
+                task=new_task,
+                connection=self._connection,
+                play_context=self._play_context,
+                loader=self._loader,
+                templar=self._templar,
+                shared_loader_obj=self._shared_loader_obj)
+            result.update(copy_action.run(task_vars=task_vars))
+        finally:
+            shutil.rmtree(local_tempdir)
         return result
diff --git a/ansible/action_plugins/merge_yaml.py b/ansible/action_plugins/merge_yaml.py
index 6ad232af82cb0e4c07e0a6c28bc416483d11afd1..371905d0d444b4f5a4aee080c0042f114fb9121e 100755
--- a/ansible/action_plugins/merge_yaml.py
+++ b/ansible/action_plugins/merge_yaml.py
@@ -17,6 +17,8 @@
 
 import inspect
 import os
+import shutil
+import tempfile
 
 from yaml import dump
 from yaml import safe_load
@@ -28,6 +30,7 @@ except ImportError:
     from yaml import Loader  # noqa: F401
 
 
+from ansible import constants
 from ansible.plugins import action
 
 
@@ -78,19 +81,31 @@ class ActionModule(action.ActionBase):
         # restore original vars
         self._templar.set_available_variables(old_vars)
 
-        remote_path = self._connection._shell.join_path(tmp, 'src')
-        xfered = self._transfer_data(remote_path,
-                                     dump(output,
-                                          default_flow_style=False))
-        new_module_args = self._task.args.copy()
-        new_module_args.update(
-            dict(
-                src=xfered
+        local_tempdir = tempfile.mkdtemp(dir=constants.DEFAULT_LOCAL_TMP)
+
+        try:
+            result_file = os.path.join(local_tempdir, 'source')
+            with open(result_file, 'wb') as f:
+                f.write(dump(output, default_flow_style=False))
+
+            new_task = self._task.copy()
+            new_task.args.pop('sources', None)
+
+            new_task.args.update(
+                dict(
+                    src=result_file
+                )
             )
-        )
-        del new_module_args['sources']
-        result.update(self._execute_module(module_name='copy',
-                                           module_args=new_module_args,
-                                           task_vars=task_vars,
-                                           tmp=tmp))
+
+            copy_action = self._shared_loader_obj.action_loader.get(
+                'copy',
+                task=new_task,
+                connection=self._connection,
+                play_context=self._play_context,
+                loader=self._loader,
+                templar=self._templar,
+                shared_loader_obj=self._shared_loader_obj)
+            result.update(copy_action.run(task_vars=task_vars))
+        finally:
+            shutil.rmtree(local_tempdir)
         return result
diff --git a/ansible/roles/common/tasks/config.yml b/ansible/roles/common/tasks/config.yml
index 63d52beee28da297a971981ae987243cd19fcd24..db9726d8ef356a00cb81ca8a90d68bf14c5ab6cf 100644
--- a/ansible/roles/common/tasks/config.yml
+++ b/ansible/roles/common/tasks/config.yml
@@ -240,6 +240,7 @@
     owner: "{{ config_owner_user }}"
     group: "{{ config_owner_group }}"
     mode: "0770"
+  ignore_errors: "{{ ansible_check_mode }}"
   when:
     - item.value.enabled | bool
     - item.key != "kolla-toolbox"
diff --git a/ansible/roles/keystone/tasks/config.yml b/ansible/roles/keystone/tasks/config.yml
index df07c35c86d070ea9d6a98801634eeaa4677f211..473f42bd3b8fcb7e9efc1b55a2515ba23a1acfa2 100644
--- a/ansible/roles/keystone/tasks/config.yml
+++ b/ansible/roles/keystone/tasks/config.yml
@@ -188,6 +188,7 @@
 - name: Save the returned from cron jobs for building the crontab
   set_fact:
     cron_jobs: "{{ (cron_jobs_json.stdout | from_json).cron_jobs }}"
+  ignore_errors: "{{ ansible_check_mode }}"
   when: keystone_token_provider == 'fernet'
 
 - name: Copying files for keystone-fernet
@@ -199,6 +200,7 @@
     mode: "0660"
   become: true
   register: keystone_fernet_confs
+  ignore_errors: "{{ ansible_check_mode }}"
   with_items:
     - { src: "crontab.j2", dest: "crontab" }
     - { src: "fernet-rotate.sh.j2", dest: "fernet-rotate.sh" }
diff --git a/releasenotes/notes/support-check-and-diff-mode-for-genconfig-97703a2ed13ab9ec.yaml b/releasenotes/notes/support-check-and-diff-mode-for-genconfig-97703a2ed13ab9ec.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c667d2ba47f6fb61eb2df4891db2a053ffcd22b8
--- /dev/null
+++ b/releasenotes/notes/support-check-and-diff-mode-for-genconfig-97703a2ed13ab9ec.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Support ansible check and diff module for generate configrations. You could
+    use ``EXTRA_OPTS='--check --diff' kolla-ansible genconfig`` to check what
+    the configration file will be like in dry-run mode.