{"record":{"id":"eee6e248916cb0c5","repo":"juanfont/headscale","slug":"autogroup-internet-can-only-be-used-in-acl-destina","errorCode":null,"errorMessage":"autogroup:internet can only be used in ACL destinations","messagePattern":"autogroup:internet can only be used in ACL destinations","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":135,"sourceCode":"\tErrUnknownAutogroup            = errors.New(\"unknown autogroup\")\n\tErrHostportMissingColon        = errors.New(\"hostport must contain a colon\")\n\tErrTypeNotSupported            = errors.New(\"type not supported\")\n\tErrInvalidAlias                = errors.New(\"invalid alias format\")\n\tErrInvalidAutoApprover         = errors.New(\"invalid auto approver format\")\n\tErrInvalidOwner                = errors.New(\"invalid owner format\")\n\tErrGroupNotDefined             = errors.New(\"group not defined in policy\")\n\tErrInvalidGroupMember          = errors.New(\"invalid group member type\")\n\tErrGroupValueNotArray          = errors.New(\"group value must be an array of users\")\n\tErrInvalidHostIP               = errors.New(\"hostname contains invalid IP address\")\n\tErrTagNotDefined               = errors.New(\"tag not found\")\n\tErrAutoApproverNotAlias        = errors.New(\"auto approver is not an alias\")\n\tErrInvalidACLAction            = errors.New(\"invalid ACL action\")\n\tErrInvalidSSHAction            = errors.New(\"invalid SSH action\")\n\tErrInvalidProtocolNumber       = errors.New(\"invalid protocol number\")\n\tErrProtocolLeadingZero         = errors.New(\"leading 0 not permitted in protocol number\")\n\tErrProtocolOutOfRange          = errors.New(\"protocol number out of range (0-255)\")\n\tErrAutogroupNotSupported       = errors.New(\"autogroup not supported in headscale\")\n\tErrAutogroupInternetSrc        = errors.New(\"autogroup:internet can only be used in ACL destinations\")\n\tErrAutogroupSelfSrc            = errors.New(\"\\\"autogroup:self\\\" not valid on the src side of a rule\")\n\tErrAutogroupNotSupportedACLSrc = errors.New(\"autogroup not supported for ACL sources\")\n\tErrAutogroupNotSupportedACLDst = errors.New(\"autogroup not supported for ACL destinations\")\n\tErrAutogroupDangerAllDst       = errors.New(\"cannot use autogroup:danger-all as a dst\")\n\tErrAutogroupNotSupportedSSHSrc = errors.New(\"autogroup not supported for SSH sources\")\n\tErrAutogroupNotSupportedSSHDst = errors.New(\"autogroup not supported for SSH destinations\")\n\tErrHostNotDefined              = errors.New(\"host not defined in policy\")\n\tErrSSHSourceAliasNotSupported  = errors.New(\"alias not supported for SSH source\")\n\tErrSSHDestAliasNotSupported    = errors.New(\"alias not supported for SSH destination\")\n\tErrUnknownField                = errors.New(\"unknown field\")\n\tErrProtocolNoSpecificPorts     = errors.New(\"protocol does not support specific ports\")\n\tErrTestEmptyAssertions         = errors.New(\"test entry must have at least one of \\\"accept\\\" or \\\"deny\\\"\")\n\tErrTestProtocolNotAllowed      = errors.New(\"test protocol must be tcp, udp, sctp, or empty\")\n\tErrTestDestinationMultiPort    = errors.New(\"test destination port must be a single port\")\n\tErrTestDestinationCIDR         = errors.New(\"test destination must be a single host, not a CIDR range\")\n\tErrAutogroupInternetTestDst    = errors.New(\"autogroup:internet not valid as a test destination\")\n\tErrSSHTestEmptySrc             = errors.New(\"SSH tests entry must have a non-empty src\")\n\tErrSSHTestEmptyDst             = errors.New(\"SSH tests entry must have at least one dst\")","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L117-L153","documentation":"Returned when autogroup:internet is used on the source side of an ACL rule (validateAutogroupForSrc, hscontrol/policy/v2/types.go:2038) or in SSH sources/destinations (types.go:2115, 2131). autogroup:internet expands to all non-private (non-RFC1918/CGNAT) addresses and only makes sense as an ACL destination ('reach the internet'); it is meaningless as a traffic source inside a tailnet.","triggerScenarios":"Policy with \"acls\": [{\"action\": \"accept\", \"src\": [\"autogroup:internet\"], \"dst\": [...]}], or \"ssh\": [{\"src\": [\"autogroup:internet\"], ...}] or an SSH dst of autogroup:internet (the SSH dst path also returns this same sentinel at types.go:2131).","commonSituations":"Misreading the autogroup's purpose and trying to write 'traffic from the internet can reach X' — headscale ACLs only govern traffic inside the tailnet plus egress, so inbound internet sourcing does not exist. Also from copy-pasting an internet-egress rule and flipping src/dst.","solutions":["Move autogroup:internet to the dst side of an ACL rule: src [your nodes], dst [\"autogroup:internet:*\"]","Remove it from SSH src/dst entirely; SSH rules only operate on tailnet identities","If you meant 'all nodes', use autogroup:member (user-owned) or autogroup:tagged on the src side"],"exampleFix":"// before\n{\"action\": \"accept\", \"proto\": \"tcp\", \"src\": [\"autogroup:internet\"], \"dst\": [\"tag:proxy:443\"]}\n\n// after\n{\"action\": \"accept\", \"proto\": \"tcp\", \"src\": [\"tag:proxy\"], \"dst\": [\"autogroup:internet:443\"]}","handlingStrategy":"validation","validationCode":"// autogroup:internet is legal ONLY in ACL dst\nfor _, acl := range acls {\n\tfor _, s := range acl.Src {\n\t\tif s == \"autogroup:internet\" {\n\t\t\treturn errors.New(\"autogroup:internet cannot be a src\")\n\t\t}\n\t}\n}","typeGuard":"func isAutogroupInternetSrc(err error) bool {\n\treturn errors.Is(err, policy.ErrAutogroupInternetSrc)\n}","tryCatchPattern":"if err := p.Validate(); err != nil {\n\tif errors.Is(err, policy.ErrAutogroupInternetSrc) {\n\t\treturn fmt.Errorf(\"move autogroup:internet to an ACL dst: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Memorize the idiom: sources are tailnet identities, internet is only ever a destination","Model internet egress as one dedicated rule: src=your nodes, dst=autogroup:internet:*","Never use autogroup:internet in ssh or sshTests sections"],"tags":["policy","autogroup","acl","ssh","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}