Sistem ERP berisi data perusahaan Anda yang paling sensitif: angka penggajian, kontrak vendor, detail rekening bank, syarat kredit pelanggan, dan catatan keuangan lengkap. Salah merancang izin dan Anda memiliki risiko kepatuhan, risiko penipuan, dan risiko pelanggaran data sekaligus. Persyaratan UU No. 27 Tahun 2022 (Undang-Undang Perlindungan Data Pribadi) memerlukan akses terkontrol dan izin berbasis peran.
Least privilege adalah prinsip fundamental: setiap pengguna hanya boleh memiliki akses ke data dan fungsi yang diperlukan untuk melakukan pekerjaan mereka, dan tidak lebih. Tantangan dalam desain ERP adalah bahwa least privilege terdengar sederhana tetapi kompleks untuk diimplementasikan — ini memerlukan peta lengkap setiap peran, setiap sumber daya, dan setiap tindakan sebelum sistem dibangun.
Mulailah dengan fungsi pekerjaan, bukan izin sistem. Untuk setiap fungsi pekerjaan dalam bisnis, tanyakan: data apa yang perlu dibaca peran ini? Data apa yang perlu dibuat? Apa yang perlu dimodifikasi? Apa yang perlu dihapus? Dalam ERP UKM Indonesia yang tipikal: Admin Sistem (semua akses), Manajer Keuangan (semua modul keuangan), Staf Keuangan (buat dan baca AP/AR, tanpa hapus, tanpa persetujuan), Pemberi Persetujuan Keuangan (baca AP/AR, setujui pembayaran), Manajer HR (semua HR), Karyawan (profil sendiri, permintaan cuti sendiri).
Pemisahan tugas (SoD) memastikan bahwa tidak ada satu pengguna yang dapat menyelesaikan transaksi signifikan secara finansial sendirian. Contoh klasik: orang yang memasukkan faktur vendor tidak boleh menjadi orang yang menyetujui pembayaran. Dalam desain ERP, aturan SoD diimplementasikan sebagai kendala alur kerja. Untuk bisnis Indonesia, SoD semakin diperlukan oleh standar audit internal dan merupakan kontrol utama yang akan diuji oleh auditor eksternal.
ERP RBAC Permission Matrix (Indonesian SME)
║ EMPLOYEE │ MGR │ FIN │ FIN │ HR │ SYS ║
RESOURCE ║ │ │ STAFF │ APPROVER│ ADMIN│ ADMIN║
══════════════════╬══════════╪═══════╪═══════╪════════╪═══════╪══════╣
Own Leave Request ║ CRUD │ R │ R │ │ CRUD │ CRUD ║
Team Leave Status ║ │ R │ │ │ CRUD │ CRUD ║
Leave Approval ║ │ APPROV│ │ │ APPROV│ ALL ║
──────────────────╫──────────┼───────┼───────┼────────┼───────┼──────╢
AP Invoice ║ │ │ CR │ R │ │ CRUD ║
AP Approval ║ │ APPROV│ │ APPROV │ │ ALL ║
AP Payment ║ │ │ R │ APPROV │ │ CRUD ║
──────────────────╫──────────┼───────┼───────┼────────┼───────┼──────╢
AR Invoice ║ │ │ CR │ R │ │ CRUD ║
AR Collections ║ │ │ CR │ R │ │ CRUD ║
──────────────────╫──────────┼───────┼───────┼────────┼───────┼──────╢
Salary Data ║ Own only │ │ │ │ CRUD │ CRUD ║
All Employee Data ║ │ Dept │ │ │ CRUD │ CRUD ║
──────────────────╫──────────┼───────┼───────┼────────┼───────┼──────╢
System Config ║ │ │ │ │ │ CRUD ║
User Management ║ │ │ │ │ │ CRUD ║
Audit Logs ║ │ │ │ │ R │ CRUD ║
CRUD = Create, Read, Update, Delete
R = Read only
APPROV = Can approve/reject (not create/delete)
Dept = Can see only their department's data
Own only = Can only see their own record
SoD Rules enforced by system (not policy):
• AP invoice creator ≠ AP approver (same person blocked)
• Payment amount > Rp 25M requires BOTH Manager + Finance Approver
• Audit log entries are immutable (no UPDATE or DELETE)Dari pengalaman saya mengimplementasikan ERP di Commsult: buat matriks izin sebelum Anda membangun sistem. Matriks memiliki peran sebagai kolom dan tindakan sistem sebagai baris. Setiap sel adalah Izinkan, Tolak, atau Bersyarat. Tinjau matriks izin dengan fungsi audit internal sebelum pengembangan dimulai.
Akses tingkat modul adalah lapisan pertama keamanan. Tetapi beberapa data memerlukan kontrol yang lebih halus. Keamanan tingkat bidang membatasi bidang mana dalam catatan yang dapat dilihat atau diedit pengguna. Keamanan tingkat catatan membatasi catatan mana yang dapat diakses pengguna dalam modul.
// NestJS: Role-Based Access Control + Separation of Duties
// 1. Define roles enum
export enum UserRole {
EMPLOYEE = 'employee',
MANAGER = 'manager',
FINANCE_STAFF = 'finance_staff',
FINANCE_APPROVER = 'finance_approver',
HR_ADMIN = 'hr_admin',
SYSTEM_ADMIN = 'system_admin',
}
// 2. Custom decorator for role-based route protection
export const Roles = (...roles: UserRole[]) =>
SetMetadata('roles', roles);
// 3. Guard enforces roles at API level
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<UserRole[]>(
'roles',
[context.getHandler(), context.getClass()]
);
if (!requiredRoles) return true;
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some(role => user.roles?.includes(role));
}
}
// 4. SoD enforcement: AP invoice approval
@Patch(':id/approve')
@Roles(UserRole.MANAGER, UserRole.FINANCE_APPROVER)
async approveInvoice(@Param('id') id: string, @CurrentUser() user: User) {
const invoice = await this.apService.findOne(id);
// SoD check: creator cannot approve their own invoice
if (invoice.createdById === user.id) {
throw new ForbiddenException(
'You cannot approve an invoice you created (separation of duties)'
);
}
return this.apService.approve(id, user.id);
}
// 5. Field-level security: salary data
@Get(':id')
async getEmployee(@Param('id') id: string, @CurrentUser() user: User) {
const employee = await this.hrService.findOne(id);
// Non-HR roles cannot see salary fields
if (!user.roles.includes(UserRole.HR_ADMIN) &&
!user.roles.includes(UserRole.SYSTEM_ADMIN)) {
const { baseSalary, bankAccount, ...safeFields } = employee;
return safeFields;
}
return employee;
}Izin mengontrol apa yang dapat dilakukan pengguna. Jejak audit merekam apa yang sebenarnya mereka lakukan. Jejak audit ERP yang lengkap menangkap: siapa melakukan tindakan, tindakan apa yang dilakukan, apa yang berubah, kapan terjadi, dan dari mana. Jejak audit tidak dapat dinegosiasikan untuk data keuangan.
Di hampir setiap sistem ERP yang pernah saya audit, ada lebih banyak akun admin dari yang diperlukan, dan akun admin tersebut digunakan untuk pekerjaan sehari-hari. Praktik terbaik: setiap orang memiliki tepat satu akun dengan izin least-privilege untuk peran mereka. Akun admin adalah akun terpisah yang hanya digunakan untuk administrasi sistem, dengan setiap sesi dicatat.
Izin yang dirancang saat go-live akan menyimpang dari realitas. Staf mengubah peran. Akses sementara yang diberikan untuk proyek tidak pernah dicabut. Akun mantan karyawan tetap aktif. Tinjauan akses kuartalan — di mana izin setiap pengguna ditinjau dan disertifikasi oleh manajer mereka — adalah kontrol standar.
UU PDP Indonesia (Undang-Undang Perlindungan Data Pribadi, No. 27 Tahun 2022) menetapkan persyaratan tentang bagaimana data pribadi diakses dan dilindungi. Untuk sistem ERP yang berisi data pribadi karyawan (nama, alamat, NPWP, gaji, rekening bank, informasi kesehatan untuk BPJS), akses harus dibatasi pada mereka yang memiliki kebutuhan sah, akses harus dicatat, dan subjek data memiliki hak untuk mengetahui siapa yang mengakses data mereka.