Skip to content

Commit

Permalink
Merge pull request #6752 from inverse-inc/feature/kandji
Browse files Browse the repository at this point in the history
Feature/kandji
  • Loading branch information
jrouzierinverse committed Jan 25, 2022
2 parents f35a015 + 3e0a885 commit cf64d85
Show file tree
Hide file tree
Showing 11 changed files with 498 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/installation/integrating_provisioning_agents.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,7 @@ include::provisioner/intune.asciidoc[]
=== Google Chromebook Provisioner
include::provisioner/google_chrome_provisioner.asciidoc[]
=== Kandji
include::provisioner/kandji.asciidoc[]
124 changes: 124 additions & 0 deletions docs/installation/provisioner/kandji.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// to display images directly on GitHub
ifdef::env-github[]
:encoding: UTF-8
:lang: en
:doctype: book
:toc: left
:imagesdir: ../../images
endif::[]

////

This file is part of the PacketFence project.

See PacketFence_Installation_Guide.asciidoc
for authors, copyright and license information.

////
//=== Kandji
==== Configure Kandji
First of all you will need to configure the basic functionality of Kandji using their documentation and enable a blueprint to apply on your devices.
==== Create an API user
Next, we will need a user that has the rights to access the Kandji API in order to verify the state of the devices directly from PacketFence.
In the Kandji admin panel, first go in the 'Settings' tab and then in 'Access'.
Note down the value of `Your organization’s API URL` for usage in the PacketFence configuration.
Now, click 'Add token' under 'API token'.
Create your API token by giving it a meaningful name and you will then be presented the API token
Note the API token for usage in the PacketFence configuration, then hit 'Next'.
==== Configure the API permissions
After creating your API token, you will be offered the option to configure the API permissions for the token, you should select the following permissions:
[options="compact"]
* Device list (`/devices`)
* Device ID (`/devices/{device_id}`)
==== Configure PacketFence
In PacketFence, MDM are referred to as provisioners.
This will walk you through adding Kandji as a provisioner.
===== Create the provisioner
Login in the PacketFence administration interface, then go in the 'Configuration' tab, then in 'Provisioners'.
Click 'Add provisioner' then select 'Kandji'.
Now configure this new provisioner with the information you got above.
[options="compact"]
* The API token is the token you obtained in the instructions above
* The host is obtained by the value of your organization's API URL. For example, if your API URL is `https://foo.clients.us-1.kandji.io/api/v1/`, the host will be `foo.clients.us-1.kandji.io`
* The enroll URL can be obtained in the 'Add devices' menu of the Kandji admin panel under 'Enrollment Portal Link'
===== Add the provisioner to the connection profile
In order for the provisioner to be used by your captive portal you need to add it in its configuration.
Go in 'Connection Profiles', then select the portal you want to modify and add your new provisioner in the list.
==== Add the necessary passthroughs
NOTE: This step is only necessary if you wish to enroll devices via the PacketFence captive-portal. Adding these passthroughs may prevent the Apple CNA (Captive-Network Assistant) from opening when the user is unregistered.
Next, still in the PacketFence administration console, go in 'Fencing' in the left menu, then scroll then to 'Passthroughs'.
Check the 'Passthrough' box above the field and add the following domains to the passthrough list.
[options="compact"]
* `<your instance>.<your region>.kandji.io` (this is your API URL)
* `*.devices.<your region>.kandji.io` (you can obtain your region from the API URL)
* `*.hs-analytics.net`
* `*.hs-banner.com`
* `*.hs-scripts.com`
* `*.hsadspixel.net`
* `*.hubapi.com`
* `*.hubspot.com`
* `*.kandji.io`
* `*.push.apple.com`
* `*.usemessages.com`
* `*.web-api.kandji.io`
* `albert.apple.com`
* `deviceenrollment.apple.com`
* `deviceservices-external.apple.com`
* `gateway.icloud.com`
* `gdmf.apple.com`
* `gs.apple.com`
* `humb.apple.com`
* `identity.apple.com`
* `iprofiles.apple.com`
* `kandji-prd-managed-library-items.s3.amazonaws.com`
* `kandji-prd.s3.amazonaws.com`
* `mdmenrollment.apple.com`
* `setup.icloud.com`
* `sq-device.apple.com`
* `static.ips.apple.com`
* `tbsc.apple.com`
* `time-ios.apple.com`
* `time-macos.apple.com`
* `time.apple.com`
* `vpp.itunes.apple.com`
===== Restart PacketFence
In order to enable the boarding passthrough for the device enrollment, you will need to restart the iptables service of PacketFence.
You can do this using the command line by doing '/usr/local/pf/bin/pfcmd service iptables restart' or in the administration interface under 'Status / Services'.
==== Testing
You can now test that Kandji enrollment is mandatory after the device registration.
Connect a device to your test network and register like you normally would.
At the end of the registration process you will be presented a page asking you to install the Kandji MDM on your device.
After you install the agent click 'Continue'. If your access is enabled than this means the connectivity between PacketFence and Kandji is good.
19 changes: 19 additions & 0 deletions html/captive-portal/templates/provisioner/kandji.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

<div class="o-layout--center u-padding">
<h5>[% i18n("To complete your network activation you need to install the Kandji MDM client.") %]</h5>
<p>[% i18n("Once the application is installed, click 'Continue' to activate your network connection") %]</p>

<div class="o-layout">
<div class="o-layout__item u-1/1 u-2/3@tablet u-3/5@desktop">
<a href="[% provisioner.enroll_url %]" class="c-btn c-btn--primary u-1/1" target="_blank">
<div class="o-flag o-flag--light o-flag--center">
<div class="o-flag__img">[% svgIcon(id='apple-icon',size='small') %]</div>
<p class="o-flag__body">[% i18n("Click here to access the enrollment page") %]</p>
</div>
</a>
<a href="/captive-portal" class="c-btn c-btn--secondary c-btn--ghost u-1/1 u-margin-top">
[% i18n("Continue") %]
</a>
</div>


Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package pfappserver::Form::Config::Provisioning::kandji;

=head1 NAME
pfappserver::Form::Config::Provisioning
=head1 DESCRIPTION
=cut

use HTML::FormHandler::Moose;
extends 'pfappserver::Form::Config::Provisioning';
with 'pfappserver::Base::Form::Role::Help';

has_field 'api_token' =>
(
type => 'ObfuscatedText',
required => 1,
);

has_field 'host' =>
(
type => 'Text',
required => 1,
);

has_field 'port' =>
(
type => 'Port',
default => pf::provisioner::kandji->meta->get_attribute('port')->default,
);

has_field 'protocol' =>
(
type => 'Select',
options => [{ label => 'http', value => 'http' }, { label => 'https' , value => 'https' }],
default => pf::provisioner::kandji->meta->get_attribute('protocol')->default,
);

has_field 'enroll_url' =>
(
type => 'Text',
default => pf::provisioner::kandji->meta->get_attribute('enroll_url')->default,
);


=head1 COPYRIGHT
Copyright (C) 2005-2021 Inverse inc.
=head1 LICENSE
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
=cut

__PACKAGE__->meta->make_immutable unless $ENV{"PF_SKIP_MAKE_IMMUTABLE"};
1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<template>
<base-form
:form="form"
:meta="meta"
:schema="schema"
:isLoading="isLoading"
>
<form-group-identifier namespace="id"
:column-label="$i18n.t('Provisioner name')"
:disabled="!isNew && !isClone"
/>

<form-group-description namespace="description"
:column-label="$i18n.t('Description')"
/>

<form-group-enforce namespace="enforce"
:column-label="$i18n.t('Enforce')"
:text="$i18n.t('Whether or not the provisioner should be enforced. This will trigger checks to validate the device is compliant with the provisioner during RADIUS authentication and on the captive portal.')"
/>

<form-group-auto-register namespace="autoregister"
:column-label="$i18n.t('Auto register')"
:text="$i18n.t('Whether or not devices should be automatically registered on the network if they are authorized in the provisioner.')"
/>

<form-group-apply-role namespace="apply_role"
:column-label="$i18n.t('Apply role')"
:text="$i18n.t('When enabled, this will apply the configured role to the endpoint if it is authorized in the provisioner.')"
/>

<form-group-role-to-apply namespace="role_to_apply"
:column-label="$i18n.t('Role to apply')"
:text="$i18n.t(`When 'Apply role' is enabled, this defines the role to apply when the device is authorized with the provisioner.`)"
/>

<form-group-category namespace="category"
:column-label="$i18n.t('Roles')"
:text="$i18n.t('Nodes with the selected roles will be affected.')"
/>

<form-group-oses namespace="oses"
:column-label="$i18n.t('OS')"
:text="$i18n.t('Nodes with the selected OS will be affected.')"
/>

<form-group-api-token namespace="api_token"
:column-label="$i18n.t('API token')"
/>

<form-group-protocol namespace="protocol"
:column-label="$i18n.t('Protocol')"
/>

<form-group-host namespace="host"
:column-label="$i18n.t('Host')"
/>

<form-group-port namespace="port"
:column-label="$i18n.t('Port')"
/>

<form-group-enroll-url namespace="enroll_url"
:column-label="$i18n.t('Enroll URL')"
:text="$i18n.t('Which URL the endpoints should use to enroll. This should point to the Kandji self-service portal. When empty, it will default to the /enroll path on the protocol+host+port defined above which is Kandji\'s default')"
/>

</base-form>
</template>
<script>
import { BaseForm } from '@/components/new/'
import {
FormGroupApiToken,
FormGroupApplyRole,
FormGroupAutoRegister,
FormGroupCategory,
FormGroupDescription,
FormGroupEnforce,
FormGroupEnrollUrl,
FormGroupHost,
FormGroupIdentifier,
FormGroupOses,
FormGroupPort,
FormGroupProtocol,
FormGroupRoleToApply
} from './'
const components = {
BaseForm,
FormGroupApiToken,
FormGroupApplyRole,
FormGroupAutoRegister,
FormGroupCategory,
FormGroupDescription,
FormGroupEnforce,
FormGroupEnrollUrl,
FormGroupHost,
FormGroupIdentifier,
FormGroupOses,
FormGroupPort,
FormGroupProtocol,
FormGroupRoleToApply
}
import { useForm as setup, useFormProps as props } from '../_composables/useForm'
// @vue/component
export default {
name: 'form-type-kandji',
inheritAttrs: false,
components,
props,
setup
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import FormTypeDpsk from './FormTypeDpsk'
import FormTypeIbm from './FormTypeIbm'
import FormTypeIntune from './FormTypeIntune'
import FormTypeJamf from './FormTypeJamf'
import FormTypeKandji from './FormTypeKandji'
import FormTypeMobileconfig from './FormTypeMobileconfig'
import FormTypeMobileiron from './FormTypeMobileiron'
import FormTypeOpswat from './FormTypeOpswat'
Expand All @@ -50,6 +51,7 @@ const components = {
FormTypeIbm,
FormTypeIntune,
FormTypeJamf,
FormTypeKandji,
FormTypeMobileconfig,
FormTypeMobileiron,
FormTypeOpswat,
Expand Down Expand Up @@ -78,6 +80,7 @@ export const setup = (props) => {
case 'ibm': return FormTypeIbm //break
case 'intune': return FormTypeIntune //break
case 'jamf': return FormTypeJamf //break
case 'kandji': return FormTypeKandji //break
case 'mobileconfig': return FormTypeMobileconfig //break
case 'mobileiron': return FormTypeMobileiron //break
case 'opswat': return FormTypeOpswat //break
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export {
BaseFormGroupInput as FormGroupAndroidAgentDownloadUri,
BaseFormGroupInput as FormGroupAndroidDownloadUri,
BaseFormGroupInputPassword as FormGroupApiPassword,
BaseFormGroupInputPassword as FormGroupApiToken,
BaseFormGroupInput as FormGroupApiUri,
BaseFormGroupInput as FormGroupApiUsername,
BaseFormGroupInput as FormGroupApplicationIdentifier,
Expand All @@ -52,6 +53,7 @@ export {
BaseFormGroupToggleDisabledEnabled as FormGroupDpskUseLocalPassword,
BaseFormGroupChosenOne as FormGroupEapType,
BaseFormGroupToggleDisabledEnabled as FormGroupEnforce,
BaseFormGroupInput as FormGroupEnrollUrl,
BaseFormGroupInputNumber as FormGroupExpiresIn,
BaseFormGroupInputNumber as FormGroupExpiresJitter,
BaseFormGroupInput as FormGroupHost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const provisioningTypes = {
dpsk: i18n.t('DPSK'),
ibm: i18n.t('IBM'),
jamf: i18n.t('Jamf'),
kandji: i18n.t('Kandji'),
mobileconfig: i18n.t('Apple Devices'),
mobileiron: i18n.t('Mobileiron'),
opswat: i18n.t('OPSWAT'),
Expand Down
Loading

0 comments on commit cf64d85

Please sign in to comment.