Configuring Horizon
coollabsio/coolify
A skill your agent uses whenever the user mentions Horizon by name in a Laravel context.
Identity and access management: RBAC, least privilege, MFA, quarterly reviews per ISO 27001 A.5.15, A.8.2, A.8.3
$ npx skills add Hack23/cia --skill access-control-policy -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install Hack23/cia access-control-policy --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/access-control-policy .claude/skills/access-control-policy && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "access-control-policy" agent skill from https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policy into .claude/skills/access-control-policy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "access-control-policy", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policyType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add Hack23/cia --skill access-control-policy -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install Hack23/cia access-control-policy --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.github/skills/access-control-policy .agents/skills/access-control-policy && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "access-control-policy" agent skill from https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policy into .agents/skills/access-control-policy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "access-control-policy", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Hack23/cia --skill access-control-policy -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install Hack23/cia access-control-policy --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.github/skills/access-control-policy .cursor/skills/access-control-policy && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "access-control-policy" agent skill from https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policy into .cursor/skills/access-control-policy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "access-control-policy", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/Hack23/cia.git --path .github/skills/access-control-policy--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add Hack23/cia --skill access-control-policy -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install Hack23/cia access-control-policy --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.github/skills/access-control-policy .gemini/skills/access-control-policy && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "access-control-policy" agent skill from https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policy into .gemini/skills/access-control-policy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "access-control-policy", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install Hack23/cia access-control-policyInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add Hack23/cia --skill access-control-policy -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .github/skills && cp -r skills-src/.github/skills/access-control-policy .github/skills/access-control-policy && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "access-control-policy" agent skill from https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policy into .github/skills/access-control-policy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "access-control-policy", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Hack23/cia --skill access-control-policy -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install Hack23/cia access-control-policy --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.github/skills/access-control-policy .opencode/skills/access-control-policy && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "access-control-policy" agent skill from https://github.com/Hack23/cia/tree/master/.github/skills/access-control-policy into .opencode/skills/access-control-policy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "access-control-policy", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
access-control-policyIdentity and access management: RBAC, least privilege, MFA, quarterly reviews per ISO 27001 A.5.15, A.8.2, A.8.3
Access Control Policy is an agent skill from Hack23/cia. Identity and access management: RBAC, least privilege, MFA, quarterly reviews per ISO 27001 A.5.15, A.8.2, A.8.3
Its SKILL.md is about 6.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering Authorization and RBAC. The repository describes itself as: Citizen Intelligence Agency. Open-source intelligence platform analyzing Swedish political activities using AI and data visualization. Tracks politicians, government… The licence is Apache-2.0.
Read from SKILL.md and the folder at commit 6a9797b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
jqawsghFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Access Control Policy loads about 6.8k tokens when it runs. Until then it costs about 34 tokens; SKILL.md has 817 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from Hack23/cia at commit 6a9797b, republished under its Apache-2.0 licence (© Hack23). 817 words, ~6,846 tokens.
.claude/skills/access-control-policy/SKILL.md (or your agent's skills folder).This skill provides systematic guidance for implementing zero-trust access control within the CIA platform, ensuring identity-centric security through role-based access control (RBAC), least privilege principle, multi-factor authentication (MFA), and regular access reviews per ISO 27001 A.5.15, A.8.2, and A.8.3.
Apply this skill when:
Do NOT skip for:
graph TD
subgraph Identity["🔐 Identity Provider"]
PRIMARY["Primary IdP<br/>🔐 MFA Enforced<br/>Central Authentication"]
end
subgraph Cloud["☁️ Cloud Infrastructure"]
IDC["AWS Identity Center<br/>🔐 SSO + MFA"]
IAM["IAM Roles<br/>🛡️ Least Privilege"]
ACCOUNTS["AWS Accounts<br/>📊 Federated Access"]
end
subgraph Dev["📝 Development"]
GITHUB["GitHub Organization<br/>🔐 MFA Required"]
CICD["CI/CD Pipeline<br/>🔑 Service Accounts"]
end
subgraph Business["💼 Business Systems"]
FINANCE["Financial Systems<br/>💰 Hardware Token"]
MARKETING["Marketing Tools<br/>📱 Platform MFA"]
SECURITY["Security Tools<br/>🛡️ Enhanced MFA"]
end
PRIMARY --> IDC
PRIMARY --> GITHUB
PRIMARY --> FINANCE
IDC --> IAM
IDC --> ACCOUNTS
GITHUB --> CICD
style Identity fill:#1565C0
style Cloud fill:#4CAF50
style Dev fill:#FF9800
style Business fill:#7B1FA2Integration with Classification Framework:
| Asset Category | Classification | Access Method | MFA Requirement | Session Timeout | Review Frequency |
|---|---|---|---|---|---|
| RESTRICTED Data | Extreme | Hardware MFA + Zero Trust | FIDO2 + Backup | 1 hour | Monthly |
| Cloud Infrastructure | Very High | Identity Center SSO | Hardware + TOTP | 4 hours | Monthly |
| Development Platform | High | Platform MFA + SSH Keys | TOTP + SSH Cert | 8 hours | Quarterly |
| Financial Systems | Very High | Provider MFA | Hardware Token | 1 hour | Monthly |
| Business Intelligence | Moderate | SSO Integration | TOTP | 24 hours | Semi-Annual |
| Marketing Platforms | Public/Internal | Platform Native | Platform MFA | 7 days | Annual |
Permission Levels and Scope:
/**
* RBAC role hierarchy for CIA platform
*
* Implements ISO 27001 A.8.2 (Privileged access rights)
*
* @see <a href="https://github.com/Hack23/ISMS-PUBLIC/blob/main/Access_Control_Policy.md">Access Control Policy</a>
*/
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
public class SecurityConfig {
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
// RBAC hierarchy: higher roles inherit lower role permissions
hierarchy.setHierarchy(
"ROLE_ADMIN > ROLE_PARTY_ANALYST\n" +
"ROLE_PARTY_ANALYST > ROLE_AUTHENTICATED_USER\n" +
"ROLE_AUTHENTICATED_USER > ROLE_GUEST"
);
return hierarchy;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
// PUBLIC: No authentication required
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/", "/login", "/register").permitAll()
// INTERNAL: Authentication required
.requestMatchers("/api/internal/**").authenticated()
// CONFIDENTIAL: Specific roles required
.requestMatchers("/api/party-financial/**")
.hasRole("PARTY_ANALYST")
// RESTRICTED: Admin only with MFA
.requestMatchers("/api/admin/**")
.hasRole("ADMIN")
.access("@mfaVerifier.isMfaAuthenticated(authentication)")
// Default: Require authentication
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
// Session timeout based on access level
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
)
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
return http.build();
}
}| Role | Scope | Permissions | Use Cases | Access Pattern |
|---|---|---|---|---|
| ROLE_ADMIN | System-wide | Full access, user management, security config | Emergency operations, security incidents | Break-glass only |
| ROLE_PARTY_ANALYST | Party data | Read/write party financial records, voting analysis | Political analysis, report generation | Daily operations |
| ROLE_AUTHENTICATED_USER | Public + internal | Read public data, basic operations | Registered users, researchers | Standard usage |
| ROLE_GUEST | Public only | Read public voting records, party information | Anonymous visitors | Public access |
/**
* Service-level access control with least privilege
*
* Implements ISO 27001 A.8.2 - Privileged access rights
*/
@Service
public class PartyFinancialService {
private final AuditLogger auditLogger;
private final PartyFinancialRepository repository;
// CONFIDENTIAL data requires specific role
@PreAuthorize("hasRole('PARTY_ANALYST') or hasRole('ADMIN')")
@PostAuthorize("returnObject.userId == authentication.principal.username or hasRole('ADMIN')")
public PartyFinancialRecord getFinancialRecord(Long recordId) {
auditLogger.logAccess(
"CONFIDENTIAL",
"party_financial_record",
recordId,
SecurityContextHolder.getContext().getAuthentication().getName()
);
return repository.findById(recordId)
.orElseThrow(() -> new AccessDeniedException("Record not found or access denied"));
}
// Write operations require explicit role check
@PreAuthorize("hasRole('PARTY_ANALYST')")
@Audited(action = "CREATE", resourceType = "party_financial_record")
public PartyFinancialRecord createRecord(PartyFinancialRecord record) {
// Validation and business logic
return repository.save(record);
}
// Admin-only operations with MFA verification
@PreAuthorize("hasRole('ADMIN') and @mfaVerifier.isMfaAuthenticated(authentication)")
@Audited(action = "DELETE", resourceType = "party_financial_record", severity = "HIGH")
public void deleteRecord(Long recordId) {
auditLogger.logPrivilegedAction(
"DELETE_FINANCIAL_RECORD",
recordId,
SecurityContextHolder.getContext().getAuthentication().getName()
);
repository.deleteById(recordId);
}
}graph TD
subgraph Access["🔐 Access Levels"]
ADMIN["Admin Access<br/>🚨 Break-Glass"]
PRIVILEGED["Privileged Data<br/>💰 Financial Systems"]
STANDARD["Standard Access<br/>📊 Business Data"]
PUBLIC["Public Access<br/>🌐 No Authentication"]
end
subgraph MFA["🔑 MFA Methods"]
HARDWARE["Hardware Token<br/>🔐 FIDO2, YubiKey"]
TOTP["TOTP App<br/>📱 Authenticator"]
SMS["SMS Backup<br/>📞 Secondary"]
PLATFORM["Platform Native<br/>🏢 GitHub, AWS"]
end
subgraph Verify["✅ Verification"]
CONTINUOUS["Continuous Verification<br/>⏱️ Session Monitoring"]
PERIODIC["Periodic Re-auth<br/>🔄 Timeout-Based"]
ONETIME["One-Time Verification<br/>✅ Login Only"]
end
ADMIN --> HARDWARE
PRIVILEGED --> HARDWARE
PRIVILEGED --> TOTP
STANDARD --> TOTP
STANDARD --> PLATFORM
HARDWARE --> CONTINUOUS
TOTP --> PERIODIC
PLATFORM --> ONETIME
style Access fill:#1565C0
style MFA fill:#FF9800
style Verify fill:#4CAF50/**
* MFA verification service
*
* Implements ISO 27001 A.5.17 - Authentication information
*/
@Service
public class MfaVerificationService {
private final TotpService totpService;
private final AuditLogger auditLogger;
/**
* Verify MFA token for privileged operations
*
* @param authentication Current authentication
* @return true if MFA verified within acceptable window
*/
public boolean isMfaAuthenticated(Authentication authentication) {
if (authentication == null || !authentication.isAuthenticated()) {
return false;
}
Object principal = authentication.getPrincipal();
if (!(principal instanceof UserDetails)) {
return false;
}
UserDetails user = (UserDetails) principal;
String username = user.getUsername();
// Check if MFA verified within last hour
LocalDateTime mfaVerifiedAt = getMfaVerificationTime(username);
LocalDateTime now = LocalDateTime.now();
if (mfaVerifiedAt == null ||
Duration.between(mfaVerifiedAt, now).toHours() >= 1) {
auditLogger.logMfaRequired(username);
return false;
}
return true;
}
/**
* Verify TOTP code and update verification timestamp
*/
public boolean verifyTotpCode(String username, String totpCode) {
boolean isValid = totpService.verifyCode(username, totpCode);
if (isValid) {
updateMfaVerificationTime(username, LocalDateTime.now());
auditLogger.logMfaSuccess(username);
} else {
auditLogger.logMfaFailure(username);
}
return isValid;
}
/**
* Require MFA re-verification for privileged operation
*/
public void requireMfaReVerification(String username) {
clearMfaVerificationTime(username);
auditLogger.logMfaRequired(username, "PRIVILEGED_OPERATION");
}
}
/**
* MFA controller for verification flow
*/
@RestController
@RequestMapping("/api/auth/mfa")
public class MfaController {
private final MfaVerificationService mfaService;
@PostMapping("/verify")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<MfaVerificationResponse> verifyMfa(
@RequestBody @Valid MfaVerificationRequest request,
Authentication authentication) {
String username = authentication.getName();
boolean isValid = mfaService.verifyTotpCode(username, request.getTotpCode());
if (isValid) {
return ResponseEntity.ok(new MfaVerificationResponse(true, "MFA verified"));
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new MfaVerificationResponse(false, "Invalid MFA code"));
}
}
@GetMapping("/status")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<MfaStatusResponse> getMfaStatus(Authentication authentication) {
String username = authentication.getName();
boolean isMfaVerified = mfaService.isMfaAuthenticated(authentication);
return ResponseEntity.ok(new MfaStatusResponse(isMfaVerified));
}
}/**
* Dynamic session timeout based on data classification
*/
@Configuration
public class SessionConfig {
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
/**
* Configure session timeout based on access level
*/
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
/**
* Session timeout customizer
*/
@Component
public class SessionTimeoutCustomizer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Default session timeout: 30 minutes
servletContext.setSessionTimeout(30);
}
}
/**
* Dynamic timeout adjustment based on role
*/
@Component
public class DynamicSessionTimeoutManager {
public int getSessionTimeout(Authentication authentication) {
Collection<? extends GrantedAuthority> authorities =
authentication.getAuthorities();
// ADMIN: 1 hour (RESTRICTED data access)
if (authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
return 60;
}
// PARTY_ANALYST: 4 hours (CONFIDENTIAL data access)
if (authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_PARTY_ANALYST"))) {
return 240;
}
// AUTHENTICATED_USER: 8 hours (INTERNAL data access)
if (authorities.stream().anyMatch(a -> a.getAuthority().equals("ROLE_AUTHENTICATED_USER"))) {
return 480;
}
// Default: 30 minutes
return 30;
}
}
}graph TD
START["🔍 Start Access Review"] --> EXTRACT["📊 Extract Access Data"]
EXTRACT --> ANALYZE{"📈 Analysis"}
ANALYZE --> DORMANT["🚫 Identify Dormant Accounts<br/>>90 days no activity"]
ANALYZE --> EXCESSIVE["⚠️ Identify Excessive Permissions<br/>More than role requires"]
ANALYZE --> SEGREGATION["🔀 Check Segregation of Duties<br/>Incompatible roles"]
DORMANT --> REVIEW{"👤 CEO Review"}
EXCESSIVE --> REVIEW
SEGREGATION --> REVIEW
REVIEW -->|Revoke| REVOKE["🔒 Revoke Access"]
REVIEW -->|Retain| DOCUMENT["📝 Document Justification"]
REVIEW -->|Modify| ADJUST["⚙️ Adjust Permissions"]
REVOKE --> AUDIT["📋 Audit Trail"]
DOCUMENT --> AUDIT
ADJUST --> AUDIT
AUDIT --> REPORT["📊 Review Report"]
REPORT --> STORE["💾 Store Evidence"]
style START fill:#1565C0
style REVIEW fill:#FF9800
style AUDIT fill:#4CAF50#!/bin/bash
# Quarterly Access Review Script
# Implements ISO 27001 A.5.18 - Access rights review
#
# Usage: ./quarterly-access-review.sh
set -euo pipefail
REPORT_DATE=$(date +%Y-%m-%d)
REVIEW_PERIOD_DAYS=90
REPORT_FILE="access-review-${REPORT_DATE}.md"
echo "# Quarterly Access Review - ${REPORT_DATE}" > "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
# 1. Identify dormant accounts
echo "## Dormant Accounts (>90 days inactive)" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
# AWS IAM Access Analyzer - unused access detection
aws accessanalyzer list-analyzers --region us-east-1 --output json | \
jq -r '.analyzers[] | select(.status=="ACTIVE") | .name' | \
while read -r analyzer; do
echo "### AWS Analyzer: ${analyzer}" >> "${REPORT_FILE}"
# Get findings for unused access
aws accessanalyzer list-findings \
--analyzer-arn "arn:aws:access-analyzer:us-east-1:ACCOUNT_ID:analyzer/${analyzer}" \
--filter 'resourceType=AWS::IAM::User,status=ACTIVE' \
--region us-east-1 \
--output json | \
jq -r '.findings[] | "- User: \(.resource) - Last accessed: \(.analyzedAt)"' \
>> "${REPORT_FILE}"
done
echo "" >> "${REPORT_FILE}"
# 2. GitHub dormant users
echo "## GitHub Dormant Users" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
gh api orgs/Hack23/members --paginate | \
jq -r '.[].login' | \
while read -r user; do
# Get last activity
LAST_ACTIVITY=$(gh api "users/${user}/events" --jq '.[0].created_at' 2>/dev/null || echo "never")
if [[ "${LAST_ACTIVITY}" == "never" ]] || \
[[ $(date -d "${LAST_ACTIVITY}" +%s) -lt $(date -d "${REVIEW_PERIOD_DAYS} days ago" +%s) ]]; then
echo "- ${user}: Last activity ${LAST_ACTIVITY}" >> "${REPORT_FILE}"
fi
done
echo "" >> "${REPORT_FILE}"
# 3. Privileged access audit
echo "## Privileged Access Audit" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
# AWS IAM users with admin policies
echo "### AWS Admin Users" >> "${REPORT_FILE}"
aws iam list-users --output json | \
jq -r '.Users[].UserName' | \
while read -r user; do
# Check for admin policies
aws iam list-attached-user-policies --user-name "${user}" --output json | \
jq -r '.AttachedPolicies[] | select(.PolicyName | contains("Admin")) | .PolicyName' | \
while read -r policy; do
echo "- ${user}: ${policy}" >> "${REPORT_FILE}"
done
done
echo "" >> "${REPORT_FILE}"
# 4. MFA compliance
echo "## MFA Compliance Status" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
# AWS IAM users without MFA
echo "### AWS Users Without MFA" >> "${REPORT_FILE}"
aws iam list-users --output json | \
jq -r '.Users[].UserName' | \
while read -r user; do
MFA_DEVICES=$(aws iam list-mfa-devices --user-name "${user}" --output json | jq '.MFADevices | length')
if [[ "${MFA_DEVICES}" -eq 0 ]]; then
echo "- ${user}: No MFA configured" >> "${REPORT_FILE}"
fi
done
echo "" >> "${REPORT_FILE}"
# 5. Generate summary
echo "## Review Summary" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
echo "- Review Date: ${REPORT_DATE}" >> "${REPORT_FILE}"
echo "- Review Period: Last ${REVIEW_PERIOD_DAYS} days" >> "${REPORT_FILE}"
echo "- Reviewer: CEO" >> "${REPORT_FILE}"
echo "- Next Review Date: $(date -d '+3 months' +%Y-%m-%d)" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
echo "## Actions Required" >> "${REPORT_FILE}"
echo "" >> "${REPORT_FILE}"
echo "- [ ] Review and revoke dormant accounts" >> "${REPORT_FILE}"
echo "- [ ] Verify privileged access justifications" >> "${REPORT_FILE}"
echo "- [ ] Enforce MFA for non-compliant users" >> "${REPORT_FILE}"
echo "- [ ] Document decisions in audit trail" >> "${REPORT_FILE}"
echo "Access review report generated: ${REPORT_FILE}"# CloudFormation template for IAM Access Analyzer
Resources:
AccessAnalyzer:
Type: AWS::AccessAnalyzer::Analyzer
Properties:
AnalyzerName: cia-access-analyzer
Type: ACCOUNT
Tags:
- Key: Purpose
Value: ContinuousAccessMonitoring
- Key: ISMSControl
Value: ISO27001-A.5.18
# EventBridge rule for access findings
AccessAnalyzerEventRule:
Type: AWS::Events::Rule
Properties:
Name: access-analyzer-findings
Description: Alert on new IAM Access Analyzer findings
EventPattern:
source:
- aws.access-analyzer
detail-type:
- Access Analyzer Finding
detail:
status:
- ACTIVE
State: ENABLED
Targets:
- Arn: !GetAtt AccessAnalyzerTopic.Arn
Id: AccessAnalyzerSNS
# SNS topic for alerts
AccessAnalyzerTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: access-analyzer-findings
DisplayName: IAM Access Analyzer Findings
Subscription:
- Endpoint: security@hack23.com
Protocol: email
# Lambda for automated remediation
AccessAnalyzerRemediationFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: access-analyzer-remediation
Runtime: python3.12
Handler: index.lambda_handler
Role: !GetAtt RemediationFunctionRole.Arn
Code:
ZipFile: |
import boto3
import json
accessanalyzer = boto3.client('accessanalyzer')
iam = boto3.client('iam')
def lambda_handler(event, context):
"""
Automated remediation for Access Analyzer findings
"""
finding = event['detail']
resource = finding['resource']
finding_type = finding['resourceType']
# Log finding
print(f"Processing finding for {resource} of type {finding_type}")
# Check if unused access (>90 days)
if 'UnusedAccess' in finding.get('findingType', ''):
# Flag for manual review
add_tag_for_review(resource)
# Check for external access
if 'ExternalAccess' in finding.get('findingType', ''):
# Alert and require justification
send_alert(resource, finding)
return {
'statusCode': 200,
'body': json.dumps('Finding processed')
}
def add_tag_for_review(resource):
"""Tag resource for quarterly review"""
# Implementation specific to resource type
pass
def send_alert(resource, finding):
"""Send alert for external access"""
# Implementation for alerting
pass
Timeout: 60
Tags:
- Key: ISMSControl
Value: ISO27001-A.5.18See Segregation of Duties Policy for:
Key Access Control Aspects Supporting SoD:
Control Objective: Business requirements for controlling access to information and systems.
Implementation:
Control Objective: Allocation and use of privileged access rights restricted and controlled.
Implementation:
Control Objective: Access to information and systems restricted per access control policy.
Implementation:
Control Objective: User access rights reviewed at regular intervals.
Implementation:
PR.AC-1: Identities and credentials issued, managed, verified, revoked
PR.AC-4: Access permissions managed, incorporating least privilege
PR.AC-7: Users, devices authenticated (MFA for remote access)
CIS Control 5: Account Management
CIS Control 6: Access Control Management
© Hack23, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .github/skills/access-control-policy of Hack23/cia.
Open the folder on GitHubat commit 6a9797b
Access Control Policy next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Access Control Policy this skillHack23/cia | 239 | — | ~6.8k | Automated safety check: Pass | Apache-2.0 | |
| Configuring Horizoncoollabsio/coolify | 63k | 4 repos | ~898 | Automated safety check: Pass | MIT | |
| K8s Security PoliciesCybereason-Public/owLSM | 280 | 11 repos | ~2k | Automated safety check: Pass | GPL-2.0 | |
| Payloadpayloadcms/payload | 45k | 5 repos | ~6.2k | Automated safety check: Pass | MIT | |
| Convex Setup Authspokvulcan/poker-planning | 114 | 8 repos | ~1.8k | Automated safety check: Pass | MIT | |
| UI Auditbagofwords1/bagofwords | 458 | — | ~2.9k | Automated safety check: Pass | Custom licence |
coollabsio/coolify
A skill your agent uses whenever the user mentions Horizon by name in a Laravel context.
Cybereason-Public/owLSM
Comprehensive guide for implementing NetworkPolicy, PodSecurityPolicy, RBAC, and Pod Security Standards in Kubernetes.
payloadcms/payload
A skill your agent uses when working with Payload projects (payload.config.ts, collections, fields, hooks, access control, Payload API).
spokvulcan/poker-planning
Sets up Convex auth, identity mapping, and access control. An agent skill from spokvulcan/poker-planning.
bagofwords1/bagofwords
Exhaustively audit the UI control by control and role by role — enumerate every button, link, and input on a set of pages, write down what each is supposed to do (derived from the handler code and…
SeemSeam/claude_codex_bridge
Diagnose a named CCB agent by combining authoritative runtime and job lineage with deep read-only pane inspection, apply bounded recovery when evidence supports it, verify the result, and request…
Hack23/cia
WCAG 2.1 AA compliance, ARIA attributes, keyboard navigation, screen reader optimization for accessible political data platforms
Hack23/cia
Advanced chart types, D3.js/Vaadin Charts patterns, political data visualization, time series analysis
Hack23/cia
AI governance, EU AI Act compliance, OWASP LLM security, responsible AI practices for GitHub Copilot agents
Hack23/cia
External API integration patterns, retry logic, circuit breakers, caching, rate limiting for government data APIs
Hack23/cia
AWS CloudWatch metrics, alarms, dashboards, log insights, and application monitoring for the CIA platform
Hack23/cia
AWS security best practices, VPC security, IAM, KMS, CloudTrail, GuardDuty for CIA platform deployment
Categories
Identity and access management: RBAC, least privilege, MFA, quarterly reviews per ISO 27001 A.5.15, A.8.2, A.8.3. Access Control Policy is an agent skill from Hack23/cia.
Access Control Policy fits situations like: tasks that involve Authorization and RBAC.
Run `npx skills add Hack23/cia --skill access-control-policy -a claude-code`. Or copy the skill folder (.github/skills/access-control-policy in Hack23/cia) into .claude/skills/access-control-policy in your project. Claude Code loads it when a task matches its description.
Run `npx skills add Hack23/cia --skill access-control-policy -a codex`. Or copy the skill folder (.github/skills/access-control-policy in Hack23/cia) into .agents/skills/access-control-policy in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Hack23/cia --skill access-control-policy -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/access-control-policy, .gemini/skills/access-control-policy, .github/skills/access-control-policy and .opencode/skills/access-control-policy in your project.
Going by SKILL.md and its folder, Access Control Policy needs the command-line tools its instructions call (jq, aws and gh).
SKILL.md names 1 domain. In commands or code: github.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Access Control Policy is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.8k tokens (SKILL.md is roughly 27k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Access Control Policy: Configuring Horizon (coollabsio/coolify, 63k stars), K8s Security Policies (Cybereason-Public/owLSM, 280 stars), Payload (payloadcms/payload, 45k stars) and Convex Setup Auth (spokvulcan/poker-planning, 114 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Hack23 (a GitHub organization) maintains it in Hack23/cia, which has 239 GitHub stars. The repository holds 78 skills in this directory. The repository was last updated on October 6, 2026.
Source: Hack23/cia on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.