diff --git a/.github/workflows/kitchen.macos.yml b/.github/workflows/kitchen.macos.yml
new file mode 100644
index 0000000000000000000000000000000000000000..038ceb61e9fc32d4d1dbbf8ff9db54bd1338cb27
--- /dev/null
+++ b/.github/workflows/kitchen.macos.yml
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+# vim: ft=yaml
+---
+name: 'Kitchen (macOS)'
+'on': ['push', 'pull_request']
+
+env:
+  KITCHEN_LOCAL_YAML: 'kitchen.macos.yml'
+
+jobs:
+  test-12:
+    runs-on: 'macos-12'
+    strategy:
+      fail-fast: false
+      matrix:
+        instance:
+          - default-macos-12-latest-py3
+    steps:
+      - name: 'Check out code'
+        uses: 'actions/checkout@v2'
+      - name: 'Set up Bundler cache'
+        uses: 'actions/cache@v1'
+        with:
+          path: 'vendor/bundle'
+          key: "${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}"
+          restore-keys: "${{ runner.os }}-gems-"
+      - name: 'Run Bundler'
+        run: |
+          ruby --version
+          bundle config path vendor/bundle
+          bundle install --jobs 4 --retry 3
+      - name: 'Run Test Kitchen'
+        run: 'bundle exec kitchen verify ${{ matrix.instance }}'
+  test-11:
+    runs-on: 'macos-11'
+    strategy:
+      fail-fast: false
+      matrix:
+        instance:
+          - default-macos-11-latest-py3
+    steps:
+      - name: 'Check out code'
+        uses: 'actions/checkout@v2'
+      - name: 'Set up Bundler cache'
+        uses: 'actions/cache@v1'
+        with:
+          path: 'vendor/bundle'
+          key: "${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}"
+          restore-keys: "${{ runner.os }}-gems-"
+      - name: 'Run Bundler'
+        run: |
+          ruby --version
+          bundle config path vendor/bundle
+          bundle install --jobs 4 --retry 3
+      - name: 'Run Test Kitchen'
+        run: 'bundle exec kitchen verify ${{ matrix.instance }}'
+  test-1015:
+    runs-on: 'macos-10.15'
+    strategy:
+      fail-fast: false
+      matrix:
+        instance:
+          - default-macos-1015-latest-py3
+    steps:
+      - name: 'Check out code'
+        uses: 'actions/checkout@v2'
+      - name: 'Set up Bundler cache'
+        uses: 'actions/cache@v1'
+        with:
+          path: 'vendor/bundle'
+          key: "${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}"
+          restore-keys: "${{ runner.os }}-gems-"
+      - name: 'Run Bundler'
+        run: |
+          ruby --version
+          bundle config path vendor/bundle
+          bundle install --jobs 4 --retry 3
+      - name: 'Run Test Kitchen'
+        run: 'bundle exec kitchen verify ${{ matrix.instance }}'
diff --git a/kitchen.macos.yml b/kitchen.macos.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2528195bfaadcf18d522961f5fe3a8a446c5d04f
--- /dev/null
+++ b/kitchen.macos.yml
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# vim: ft=yaml
+---
+driver:
+  name: exec
+
+provisioner:
+  sudo: true
+  salt_install: bootstrap
+  salt_bootstrap_options: -P stable latest
+  salt_call_command: /opt/salt/bin/salt-call
+
+platforms:
+  - name: macos-12-latest-py3
+    verifier:
+      inputs:
+        saltmajorversion: 3004
+  - name: macos-11-latest-py3
+    verifier:
+      inputs:
+        saltmajorversion: 3004
+  - name: macos-1015-latest-py3
+    verifier:
+      inputs:
+        saltmajorversion: 3004
diff --git a/salt/minion.sls b/salt/minion.sls
index e1eb8b5b73e4df85e445cc82d53cb3fdd295e26b..97db5b321f6330e2d09dac88afcfe4682810276b 100644
--- a/salt/minion.sls
+++ b/salt/minion.sls
@@ -20,8 +20,8 @@ download-salt-minion:
                     {% else %}
     - skip_verify: True
                     {% endif %}
-    - user: root
-    - group: wheel
+    - user: {{ salt_settings.rootuser }}
+    - group: {{ salt_settings.rootgroup }}
     - mode: '0644'
     - unless:
       - test -n "{{ salt_settings.version }}" && '/opt/salt/bin/salt-minion --version=.*{{ salt_settings.version }}.*'
@@ -29,10 +29,13 @@ download-salt-minion:
       - macpackage: salt-minion
     - retry: {{ salt_settings.retry_options | json }}
             {%- elif "workaround https://github.com/saltstack/salt/issues/49348" %}
-  cmd.run:
-    - name: /usr/local/bin/brew install {{ salt_settings.salt_minion }}
-    - onlyif: test -x /usr/local/bin/brew
-    - runas: {{ salt_settings.rootuser }}
+  {% if salt_settings.install_packages %}
+  pkg.installed:
+    - name: {{ salt_settings.salt_minion }}
+    {%- if salt_settings.version is defined %}
+    - version: {{ salt_settings.version }}
+    {%- endif %}
+  {% endif %}
             {%- endif %}
 
 salt-minion-macos:
@@ -130,7 +133,7 @@ salt-minion:
             {%- if grains.os == 'MacOS' and salt_settings.salt_minion_pkg_source %}
       - macpackage: salt-minion
             {%- elif grains.os == 'MacOS' %}
-      - cmd: download-salt-minion
+      - pkg: download-salt-minion
             {%- else %}
       - pkg: salt-minion
             {%- endif %}
@@ -155,7 +158,7 @@ restart-salt-minion:
             {%- if grains.os == 'MacOS' and salt_settings.salt_minion_pkg_source %}
       - macpackage: salt-minion
             {%- elif grains.os == 'MacOS' %}
-      - cmd: download-salt-minion
+      - pkg: download-salt-minion
             {%- else %}
       - pkg: salt-minion
             {%- endif %}
@@ -201,7 +204,7 @@ permissions-minion-config:
         {%- if grains['kernel'] in ['FreeBSD', 'OpenBSD', 'NetBSD'] %}
         wheel
         {%- else %}
-        root
+        {{ salt_settings.rootgroup }}
         {%- endif %}
     {%- if grains['kernel'] != 'Windows' %}
     - mode: 640
@@ -221,7 +224,7 @@ salt-minion-pki-dir:
         {%- if grains['kernel'] in ['FreeBSD', 'OpenBSD', 'NetBSD'] %}
         wheel
         {%- else %}
-        root
+        {{ salt_settings.rootgroup }}
         {%- endif %}
     {%- if grains['kernel'] != 'Windows' %}
     - mode: 700
@@ -240,7 +243,7 @@ permissions-minion.pem:
         {%- if grains['kernel'] in ['FreeBSD', 'OpenBSD', 'NetBSD'] %}
         wheel
         {%- else %}
-        root
+        {{ salt_settings.rootgroup }}
         {%- endif %}
     {%- if grains['kernel'] != 'Windows' %}
     - mode: 400
@@ -261,7 +264,7 @@ permissions-minion.pub:
         {%- if grains['kernel'] in ['FreeBSD', 'OpenBSD', 'NetBSD'] %}
         wheel
         {%- else %}
-        root
+        {{ salt_settings.rootgroup }}
         {%- endif %}
     {%- if grains['kernel'] != 'Windows' %}
     - mode: 644
diff --git a/salt/osfamilymap.yaml b/salt/osfamilymap.yaml
index 6f03da81dfb15617d64ac6931edfe4f6d716f32b..e2e48a6407bedb5b84d0c508f0730f3096c54bfb 100644
--- a/salt/osfamilymap.yaml
+++ b/salt/osfamilymap.yaml
@@ -138,6 +138,7 @@ Windows:
   rootuser: {{ rootuser | d('') }}
 
 MacOS:
+  salt_master: saltstack
   salt_minion: salt
   salt_minion_pkg_source: ''
   salt_minion_pkg_hash: ''
diff --git a/test/integration/default/controls/pkgs_spec.rb b/test/integration/default/controls/pkgs_spec.rb
index 389aba19c31275e6495613ed73fdae12d4dea3cc..3bfb34b04c12cb66f760f0229739a1192d9975db 100644
--- a/test/integration/default/controls/pkgs_spec.rb
+++ b/test/integration/default/controls/pkgs_spec.rb
@@ -8,6 +8,8 @@ pkgs =
     %w[py38-salt]
   when 'windows'
     ['Salt Minion']
+  when 'mac_os_x'
+    %w[salt saltstack]
   else
     %w[salt-master salt-minion]
   end
diff --git a/test/integration/default/controls/service_spec.rb b/test/integration/default/controls/service_spec.rb
index be3dab720c873b91809706c581ccec77af9663ab..a1d58437040a9e9fd25189ec506aab7a73f11ae5 100644
--- a/test/integration/default/controls/service_spec.rb
+++ b/test/integration/default/controls/service_spec.rb
@@ -6,6 +6,14 @@ services =
     %w[salt_master salt_minion]
   when 'windows'
     %w[salt-minion]
+  when 'darwin'
+    # The following is expected but isn't yet working in the GitHub Actions
+    # macOS runners
+    # %w[com.saltstack.salt.api
+    #    com.saltstack.salt.master
+    #    com.saltstack.salt.minion
+    #    com.saltstack.salt.syndic]
+    []
   else
     %w[salt-master salt-minion]
   end
diff --git a/test/integration/default/files/_mapdata/mac_os_x-10.yaml b/test/integration/default/files/_mapdata/mac_os_x-10.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b8f0fa7c11fb33112bcf3ec90a69d3b1ba009f11
--- /dev/null
+++ b/test/integration/default/files/_mapdata/mac_os_x-10.yaml
@@ -0,0 +1,115 @@
+# yamllint disable rule:indentation rule:line-length
+# Mac OS X
+---
+values:
+  formulas_settings:
+    checkout_orig_branch: false
+    git_opts:
+      default:
+        basedir: /srv/formulas
+        baseurl: https://github.com/saltstack-formulas
+        options:
+          output_loglevel: quiet
+          rev: master
+        update: false
+    list: {}
+  salt_settings:
+    api_service: salt-api
+    api_service_details:
+      enabled: true
+      state: running
+    clean_config_d_dir: true
+    cloud:
+      template_sources:
+        maps: salt://salt/files/cloud.maps.d
+        profiles: salt://salt/files/cloud.profiles.d
+        providers: salt://salt/files/cloud.providers.d
+    config_path: /private/etc/salt
+    gitfs:
+      dulwich:
+        install_from_source: true
+      gitpython:
+        install_from_source: false
+      pygit2:
+        git:
+          install_from_package: git
+          require_state: false
+        install_from_source: true
+        libgit2:
+          build_parent_dir: /usr/src/
+          download_hash: 683d1164e361e2a0a8d52652840e2340
+          install_from_source: true
+          version: 0.23.0
+        version: 0.23.0
+    install_packages: true
+    master:
+      ext_pillar:
+      - cmd_yaml: cat /etc/salt/yaml
+      - stack:
+        - /path/to/stack1.cfg
+        - /path/to/stack2.cfg
+      - reclass:
+          inventory_base_uri: /etc/reclass
+      - saltclass:
+        - path: /srv/saltclass
+      file_roots:
+        base:
+        - /srv/salt
+      fileserver_backend:
+      - rootfs
+      gitfs_provider: gitpython
+      pillar_roots:
+        base:
+        - /srv/pillar
+    master_config_use_TOFS: false
+    master_remove_config: false
+    master_service: com.saltstack.salt.master
+    master_service_details:
+      enabled: true
+      state: running
+    minion:
+      file_roots:
+        base:
+        - /srv/salt
+      fileserver_backend:
+      - rootfs
+      master: localhost
+      master_type: str
+      pillar_roots:
+        base:
+        - /srv/pillar
+    minion_config_use_TOFS: false
+    minion_remove_config: false
+    minion_service: com.saltstack.salt.minion
+    minion_service_details:
+      enabled: true
+      state: running
+    parallel: true
+    pin_version: false
+    pkgrepo: ''
+    py_ver: py3
+    python_dulwich: python-dulwich
+    python_git: python-git
+    release: '3004'
+    restart_via_at: false
+    retry_options:
+      attempts: 5
+      interval: 10
+      splay: 10
+      until: true
+    rootgroup: staff
+    rootuser: runner
+    salt_api: salt-api
+    salt_cloud: salt-cloud
+    salt_master: saltstack
+    salt_master_macos_plist_hash: 8435331b2d48ca8f0759f216e5b15ec9171a4216b1441328c732c6906728b7c9
+    salt_minion: salt
+    salt_minion_macos_plist_hash: 26b33da12e0d8960ee96b488c8352002c22a377c19bf3df3f986a1e49eca8b20
+    salt_minion_pkg_hash: ''
+    salt_minion_pkg_source: ''
+    salt_ssh: salt-ssh
+    salt_syndic: salt-syndic
+    ssh_roster: {}
+    syndic_service: salt-syndic
+    use_pip: false
+    version: ''
diff --git a/test/integration/default/files/_mapdata/mac_os_x-11.yaml b/test/integration/default/files/_mapdata/mac_os_x-11.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b8f0fa7c11fb33112bcf3ec90a69d3b1ba009f11
--- /dev/null
+++ b/test/integration/default/files/_mapdata/mac_os_x-11.yaml
@@ -0,0 +1,115 @@
+# yamllint disable rule:indentation rule:line-length
+# Mac OS X
+---
+values:
+  formulas_settings:
+    checkout_orig_branch: false
+    git_opts:
+      default:
+        basedir: /srv/formulas
+        baseurl: https://github.com/saltstack-formulas
+        options:
+          output_loglevel: quiet
+          rev: master
+        update: false
+    list: {}
+  salt_settings:
+    api_service: salt-api
+    api_service_details:
+      enabled: true
+      state: running
+    clean_config_d_dir: true
+    cloud:
+      template_sources:
+        maps: salt://salt/files/cloud.maps.d
+        profiles: salt://salt/files/cloud.profiles.d
+        providers: salt://salt/files/cloud.providers.d
+    config_path: /private/etc/salt
+    gitfs:
+      dulwich:
+        install_from_source: true
+      gitpython:
+        install_from_source: false
+      pygit2:
+        git:
+          install_from_package: git
+          require_state: false
+        install_from_source: true
+        libgit2:
+          build_parent_dir: /usr/src/
+          download_hash: 683d1164e361e2a0a8d52652840e2340
+          install_from_source: true
+          version: 0.23.0
+        version: 0.23.0
+    install_packages: true
+    master:
+      ext_pillar:
+      - cmd_yaml: cat /etc/salt/yaml
+      - stack:
+        - /path/to/stack1.cfg
+        - /path/to/stack2.cfg
+      - reclass:
+          inventory_base_uri: /etc/reclass
+      - saltclass:
+        - path: /srv/saltclass
+      file_roots:
+        base:
+        - /srv/salt
+      fileserver_backend:
+      - rootfs
+      gitfs_provider: gitpython
+      pillar_roots:
+        base:
+        - /srv/pillar
+    master_config_use_TOFS: false
+    master_remove_config: false
+    master_service: com.saltstack.salt.master
+    master_service_details:
+      enabled: true
+      state: running
+    minion:
+      file_roots:
+        base:
+        - /srv/salt
+      fileserver_backend:
+      - rootfs
+      master: localhost
+      master_type: str
+      pillar_roots:
+        base:
+        - /srv/pillar
+    minion_config_use_TOFS: false
+    minion_remove_config: false
+    minion_service: com.saltstack.salt.minion
+    minion_service_details:
+      enabled: true
+      state: running
+    parallel: true
+    pin_version: false
+    pkgrepo: ''
+    py_ver: py3
+    python_dulwich: python-dulwich
+    python_git: python-git
+    release: '3004'
+    restart_via_at: false
+    retry_options:
+      attempts: 5
+      interval: 10
+      splay: 10
+      until: true
+    rootgroup: staff
+    rootuser: runner
+    salt_api: salt-api
+    salt_cloud: salt-cloud
+    salt_master: saltstack
+    salt_master_macos_plist_hash: 8435331b2d48ca8f0759f216e5b15ec9171a4216b1441328c732c6906728b7c9
+    salt_minion: salt
+    salt_minion_macos_plist_hash: 26b33da12e0d8960ee96b488c8352002c22a377c19bf3df3f986a1e49eca8b20
+    salt_minion_pkg_hash: ''
+    salt_minion_pkg_source: ''
+    salt_ssh: salt-ssh
+    salt_syndic: salt-syndic
+    ssh_roster: {}
+    syndic_service: salt-syndic
+    use_pip: false
+    version: ''
diff --git a/test/integration/default/files/_mapdata/mac_os_x-12.yaml b/test/integration/default/files/_mapdata/mac_os_x-12.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b8f0fa7c11fb33112bcf3ec90a69d3b1ba009f11
--- /dev/null
+++ b/test/integration/default/files/_mapdata/mac_os_x-12.yaml
@@ -0,0 +1,115 @@
+# yamllint disable rule:indentation rule:line-length
+# Mac OS X
+---
+values:
+  formulas_settings:
+    checkout_orig_branch: false
+    git_opts:
+      default:
+        basedir: /srv/formulas
+        baseurl: https://github.com/saltstack-formulas
+        options:
+          output_loglevel: quiet
+          rev: master
+        update: false
+    list: {}
+  salt_settings:
+    api_service: salt-api
+    api_service_details:
+      enabled: true
+      state: running
+    clean_config_d_dir: true
+    cloud:
+      template_sources:
+        maps: salt://salt/files/cloud.maps.d
+        profiles: salt://salt/files/cloud.profiles.d
+        providers: salt://salt/files/cloud.providers.d
+    config_path: /private/etc/salt
+    gitfs:
+      dulwich:
+        install_from_source: true
+      gitpython:
+        install_from_source: false
+      pygit2:
+        git:
+          install_from_package: git
+          require_state: false
+        install_from_source: true
+        libgit2:
+          build_parent_dir: /usr/src/
+          download_hash: 683d1164e361e2a0a8d52652840e2340
+          install_from_source: true
+          version: 0.23.0
+        version: 0.23.0
+    install_packages: true
+    master:
+      ext_pillar:
+      - cmd_yaml: cat /etc/salt/yaml
+      - stack:
+        - /path/to/stack1.cfg
+        - /path/to/stack2.cfg
+      - reclass:
+          inventory_base_uri: /etc/reclass
+      - saltclass:
+        - path: /srv/saltclass
+      file_roots:
+        base:
+        - /srv/salt
+      fileserver_backend:
+      - rootfs
+      gitfs_provider: gitpython
+      pillar_roots:
+        base:
+        - /srv/pillar
+    master_config_use_TOFS: false
+    master_remove_config: false
+    master_service: com.saltstack.salt.master
+    master_service_details:
+      enabled: true
+      state: running
+    minion:
+      file_roots:
+        base:
+        - /srv/salt
+      fileserver_backend:
+      - rootfs
+      master: localhost
+      master_type: str
+      pillar_roots:
+        base:
+        - /srv/pillar
+    minion_config_use_TOFS: false
+    minion_remove_config: false
+    minion_service: com.saltstack.salt.minion
+    minion_service_details:
+      enabled: true
+      state: running
+    parallel: true
+    pin_version: false
+    pkgrepo: ''
+    py_ver: py3
+    python_dulwich: python-dulwich
+    python_git: python-git
+    release: '3004'
+    restart_via_at: false
+    retry_options:
+      attempts: 5
+      interval: 10
+      splay: 10
+      until: true
+    rootgroup: staff
+    rootuser: runner
+    salt_api: salt-api
+    salt_cloud: salt-cloud
+    salt_master: saltstack
+    salt_master_macos_plist_hash: 8435331b2d48ca8f0759f216e5b15ec9171a4216b1441328c732c6906728b7c9
+    salt_minion: salt
+    salt_minion_macos_plist_hash: 26b33da12e0d8960ee96b488c8352002c22a377c19bf3df3f986a1e49eca8b20
+    salt_minion_pkg_hash: ''
+    salt_minion_pkg_source: ''
+    salt_ssh: salt-ssh
+    salt_syndic: salt-syndic
+    ssh_roster: {}
+    syndic_service: salt-syndic
+    use_pip: false
+    version: ''
diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml
index 777ca56af354370ea3efe0df95e3c77604b2ee6a..c566580a45126d2de8bb52a4b9b9f382689ed99b 100644
--- a/test/integration/default/inspec.yml
+++ b/test/integration/default/inspec.yml
@@ -24,4 +24,5 @@ supports:
   - platform-name: gentoo
   - platform-name: almalinux
   - platform-name: rocky
+  - platform-name: mac_os_x
   - platform: windows