Back to Blog

7-Tier Data Classification: Security Labeling Framework from Public to Top Secret

coomia-dip implements a 7-tier data classification system (A1-Public, A2-Internal Public, B1-Internal Sensitive, B2-Confidential, C1-Highly Confidential, C2-Restricted, D-Top Secret) that provides a unified metadata foundation for access control, dynamic masking, and compliance auditing. Classification labels are embedded in the Ontology Schema and propagated automatically through Protobuf in gRPC call chains. This article covers the complete framework from classification design philosophy, technical implementation, and policy engine integration to operational management.

CoomiaPublished on September 20, 202511 min read
Share this articleTwitter / X

Series: S6 Platform Engineering · Article 7 | Level: Advanced | Reading Time: 18 min

7-Tier Data Classification: Security Labeling Framework from Public to Top Secret

#TL;DR

coomia-dip implements a 7-tier data classification system (A1-Public, A2-Internal Public, B1-Internal Sensitive, B2-Confidential, C1-Highly Confidential, C2-Restricted, D-Top Secret) that provides a unified metadata foundation for access control, dynamic masking, and compliance auditing. Classification labels are embedded in the Ontology Schema and propagated automatically through Protobuf in gRPC call chains. This article covers the complete framework from classification design philosophy, technical implementation, and policy engine integration to operational management.

#1. The Need for Data Classification

#1.1 Chaos Without Classification

Without a unified data classification system, security policies are difficult to enforce consistently:

  • Insufficient permission granularity: Cannot distinguish access levels between "general customer info" and "customer SSN"
  • Ambiguous masking policies: Developers rely on intuition to determine which fields need masking, leading to inconsistent protection
  • Compliance risk: Cannot demonstrate that appropriate protective measures are applied to data of different sensitivity levels
  • Data governance blind spots: Metadata catalog lacks classification dimensions, preventing sensitivity-based search and management

#1.2 Design Motivation for 7 Tiers

The coomia-dip 7-tier classification system considers the following:

TierCodeNameDescriptionTypical Data
1A1PublicData that can be publicly releasedProduct catalogs, announcements
2A2Internal PublicFreely accessible within the organizationInternal wikis, process docs
3B1Internal SensitiveNeed-to-know accessBusiness reports, project data
4B2ConfidentialRestricted scope accessFinancial data, contracts
5C1Highly ConfidentialStrict access controlCustomer PII, medical records
6C2RestrictedMinimum necessary accessKey material, security configs
7DTop SecretNamed custodians onlyDefense/regulatory core data

#1.3 Comparison with Palantir Foundry

CapabilityPalantir Foundrycoomia-dip
Classification tiersMulti-layer Marking7-tier (A1-D)
Auto-labelingPartial supportRule engine auto-labeling
Propagation mechanismBuilt-in but opaqueExplicit Protobuf propagation
Inheritance rulesHigh-water markConfigurable inheritance policy
Masking integrationBuilt-inABAC-driven mapping

#2. Classification Model Design

#2.1 Classification Level Enumeration

Python
from enum import IntEnum

class ClassificationLevel(IntEnum):
    """Data Classification Level - 7-Tier System"""

    PUBLIC = 1               # A1 - Public
    INTERNAL_PUBLIC = 2      # A2 - Internal Public
    INTERNAL_SENSITIVE = 3   # B1 - Internal Sensitive
    CONFIDENTIAL = 4         # B2 - Confidential
    HIGHLY_CONFIDENTIAL = 5  # C1 - Highly Confidential
    RESTRICTED = 6           # C2 - Restricted
    TOP_SECRET = 7           # D  - Top Secret

    @property
    def code(self) -> str:
        return {
            1: "A1", 2: "A2", 3: "B1", 4: "B2",
            5: "C1", 6: "C2", 7: "D",
        }[self.value]

    @property
    def requires_encryption_at_rest(self) -> bool:
        return self.value >= 4  # B2 and above

    @property
    def requires_audit_on_access(self) -> bool:
        return self.value >= 3  # B1 and above

    @property
    def max_retention_days(self) -> int | None:
        return {
            5: 365 * 3,   # C1: 3 years
            6: 365 * 5,   # C2: 5 years
            7: 365 * 10,  # D: 10 years
        }.get(self.value)

#2.2 Classification Label Model

Python
class ClassificationLabel(BaseModel):
    """Data Classification Label"""

    level: ClassificationLevel = Field(description="Classification level")
    category: DataCategory = Field(description="Data category")
    sub_category: str | None = Field(default=None, description="Sub-category")

    # Label metadata
    labeled_by: str = Field(description="Labeler (person/system)")
    labeled_at: datetime = Field(description="Labeling timestamp")
    review_status: ReviewStatus = Field(default=ReviewStatus.PENDING)
    reviewed_by: str | None = Field(default=None)
    reviewed_at: datetime | None = Field(default=None)

    # Label source
    source: LabelSource = Field(description="Label source")
    confidence: float = Field(default=1.0, ge=0.0, le=1.0, description="Confidence score")

    # Compliance tags
    regulatory_tags: list[str] = Field(
        default_factory=list,
        description="Associated regulatory tags (e.g., GDPR, HIPAA)",
    )


class DataCategory(str, Enum):
    PII = "pii"                    # Personally Identifiable Information
    PHI = "phi"                    # Protected Health Information
    PCI = "pci"                    # Payment Card Industry
    FINANCIAL = "financial"
    BUSINESS = "business"
    TECHNICAL = "technical"
    OPERATIONAL = "operational"


class LabelSource(str, Enum):
    MANUAL = "manual"
    RULE_ENGINE = "rule_engine"
    ML_CLASSIFIER = "ml_classifier"
    INHERITED = "inherited"
    SCHEMA_DEFAULT = "schema_default"

#2.3 Schema Integration

Classification labels are embedded in Ontology Schema property definitions:

Python
class PropertyDefinition(BaseModel):
    """Ontology property definition with classification"""

    name: str
    display_name: str
    data_type: DataType
    description: str = ""

    classification: ClassificationLabel | None = Field(
        default=None,
        description="Property data classification label",
    )

    min_classification: ClassificationLevel | None = Field(
        default=None,
        description="Minimum classification level allowed for this property",
    )

    field_security: FieldSecurityPolicy | None = Field(default=None)


class ObjectTypeDefinition(BaseModel):
    """Object type definition with object-level classification"""

    api_name: str
    display_name: str
    description: str

    effective_classification: ClassificationLevel = Field(
        default=ClassificationLevel.PUBLIC,
    )

    properties: dict[str, PropertyDefinition]

    def compute_effective_classification(self) -> ClassificationLevel:
        """Compute effective classification (highest across all properties)"""
        max_level = ClassificationLevel.PUBLIC
        for prop in self.properties.values():
            if prop.classification and prop.classification.level > max_level:
                max_level = prop.classification.level
        return max_level

#3. Automatic Classification Engine

#3.1 Rule-Based Auto-Classification

Python
class RuleBasedClassifier:
    """Rule-based automatic classification engine"""

    def __init__(self):
        self._rules: list[ClassificationRule] = []
        self._load_default_rules()

    def _load_default_rules(self):
        self._rules = [
            # PII rules
            ClassificationRule(
                name="pii_id_number",
                pattern=r"(id_card|ssn|social_security|national_id)",
                field_type_match=["string"],
                classification=ClassificationLevel.HIGHLY_CONFIDENTIAL,
                category=DataCategory.PII,
                confidence=0.95,
            ),
            ClassificationRule(
                name="pii_phone",
                pattern=r"(phone|mobile|tel|cell)",
                field_type_match=["string"],
                classification=ClassificationLevel.CONFIDENTIAL,
                category=DataCategory.PII,
                confidence=0.90,
            ),
            ClassificationRule(
                name="pii_email",
                pattern=r"(email|mail_address)",
                field_type_match=["string"],
                classification=ClassificationLevel.CONFIDENTIAL,
                category=DataCategory.PII,
                confidence=0.90,
            ),
            ClassificationRule(
                name="pii_name",
                pattern=r"(full_name|real_name|legal_name)",
                field_type_match=["string"],
                classification=ClassificationLevel.INTERNAL_SENSITIVE,
                category=DataCategory.PII,
                confidence=0.85,
            ),
            # Financial data rules
            ClassificationRule(
                name="financial_account",
                pattern=r"(bank_card|account_number|routing_number)",
                field_type_match=["string"],
                classification=ClassificationLevel.HIGHLY_CONFIDENTIAL,
                category=DataCategory.PCI,
                confidence=0.95,
            ),
            ClassificationRule(
                name="financial_salary",
                pattern=r"(salary|compensation|wage|pay_rate)",
                field_type_match=["decimal", "float", "integer"],
                classification=ClassificationLevel.CONFIDENTIAL,
                category=DataCategory.FINANCIAL,
                confidence=0.90,
            ),
            # Health data rules
            ClassificationRule(
                name="phi_diagnosis",
                pattern=r"(diagnosis|medical_record|health_condition)",
                field_type_match=["string", "text"],
                classification=ClassificationLevel.HIGHLY_CONFIDENTIAL,
                category=DataCategory.PHI,
                confidence=0.95,
            ),
        ]

    def classify_field(
        self,
        field_name: str,
        field_type: str,
        description: str = "",
    ) -> ClassificationLabel | None:
        best_match: ClassificationRule | None = None
        best_confidence = 0.0

        text_to_match = f"{field_name} {description}".lower()

        for rule in self._rules:
            if field_type not in rule.field_type_match:
                continue
            if re.search(rule.pattern, text_to_match, re.IGNORECASE):
                if rule.confidence > best_confidence:
                    best_match = rule
                    best_confidence = rule.confidence

        if best_match is None:
            return None

        return ClassificationLabel(
            level=best_match.classification,
            category=best_match.category,
            labeled_by="rule_engine",
            labeled_at=datetime.utcnow(),
            source=LabelSource.RULE_ENGINE,
            confidence=best_match.confidence,
        )

#3.2 Classification Inheritance and Propagation

When data flows through the Ontology, classification labels must propagate correctly:

Python
class ClassificationPropagator:
    """Classification label propagator"""

    class PropagationPolicy(str, Enum):
        HIGH_WATER_MARK = "high_water_mark"
        EXPLICIT_ONLY = "explicit_only"
        INHERIT_SOURCE = "inherit_source"

    def propagate_on_transform(
        self,
        source_classifications: list[ClassificationLabel],
        transform_type: str,
        policy: PropagationPolicy = PropagationPolicy.HIGH_WATER_MARK,
    ) -> ClassificationLabel:
        if policy == self.PropagationPolicy.HIGH_WATER_MARK:
            max_level = max(c.level for c in source_classifications)
            categories = set(c.category for c in source_classifications)
            regulatory_tags = set()
            for c in source_classifications:
                regulatory_tags.update(c.regulatory_tags)

            return ClassificationLabel(
                level=max_level,
                category=categories.pop() if len(categories) == 1 else DataCategory.BUSINESS,
                labeled_by="propagation_engine",
                labeled_at=datetime.utcnow(),
                source=LabelSource.INHERITED,
                confidence=min(c.confidence for c in source_classifications),
                regulatory_tags=list(regulatory_tags),
            )

        elif policy == self.PropagationPolicy.EXPLICIT_ONLY:
            raise ValueError("Explicit policy requires manual classification")

        elif policy == self.PropagationPolicy.INHERIT_SOURCE:
            return source_classifications[0].model_copy(
                update={
                    "source": LabelSource.INHERITED,
                    "labeled_at": datetime.utcnow(),
                }
            )

#4. Protobuf Propagation Protocol

#4.1 Classification Label Protobuf Definition

PROTOBUF
syntax = "proto3";

package onto.classification.v1;

enum ClassificationLevel {
    CLASSIFICATION_LEVEL_UNSPECIFIED = 0;
    PUBLIC = 1;
    INTERNAL_PUBLIC = 2;
    INTERNAL_SENSITIVE = 3;
    CONFIDENTIAL = 4;
    HIGHLY_CONFIDENTIAL = 5;
    RESTRICTED = 6;
    TOP_SECRET = 7;
}

enum DataCategory {
    DATA_CATEGORY_UNSPECIFIED = 0;
    PII = 1;
    PHI = 2;
    PCI = 3;
    FINANCIAL = 4;
    BUSINESS = 5;
    TECHNICAL = 6;
    OPERATIONAL = 7;
}

message ClassificationLabel {
    ClassificationLevel level = 1;
    DataCategory category = 2;
    string sub_category = 3;
    string labeled_by = 4;
    google.protobuf.Timestamp labeled_at = 5;
    string source = 6;
    double confidence = 7;
    repeated string regulatory_tags = 8;
}

message FieldClassification {
    string field_name = 1;
    ClassificationLabel label = 2;
}

message ObjectClassification {
    string object_type = 1;
    ClassificationLevel effective_level = 2;
    repeated FieldClassification field_classifications = 3;
}

#4.2 gRPC Metadata Propagation

Classification information propagates between services via gRPC metadata:

Python
class ClassificationInterceptor(grpc.aio.UnaryUnaryClientInterceptor):
    """gRPC client interceptor - propagate classification context"""

    async def intercept_unary_unary(self, continuation, client_call_details, request):
        current_classification = classification_context.get()

        if current_classification:
            metadata = list(client_call_details.metadata or [])
            metadata.append((
                "x-classification-level",
                str(current_classification.level.value),
            ))
            metadata.append((
                "x-classification-category",
                current_classification.category.value,
            ))

            new_details = client_call_details._replace(metadata=metadata)
            return await continuation(new_details, request)

        return await continuation(client_call_details, request)

#5. Integration with Security Subsystems

#5.1 Access Control Integration

Classification levels directly influence ABAC policy evaluation:

Python
class ClassificationBasedAccessControl:
    """Classification-based access control"""

    CLEARANCE_MAP = {
        "public_user": ClassificationLevel.PUBLIC,
        "internal_user": ClassificationLevel.INTERNAL_SENSITIVE,
        "confidential_user": ClassificationLevel.CONFIDENTIAL,
        "secret_user": ClassificationLevel.HIGHLY_CONFIDENTIAL,
        "top_secret_user": ClassificationLevel.TOP_SECRET,
    }

    def check_access(
        self,
        user_clearance: str,
        resource_classification: ClassificationLevel,
    ) -> AccessDecision:
        max_allowed = self.CLEARANCE_MAP.get(user_clearance, ClassificationLevel.PUBLIC)

        if resource_classification <= max_allowed:
            return AccessDecision.ALLOW
        else:
            return AccessDecision.DENY

#5.2 Masking Integration

Classification levels determine masking mode selection (see S6-06 for details):

Python
CLASSIFICATION_MASKING_MAP = {
    ClassificationLevel.PUBLIC: MaskingMode.NONE,
    ClassificationLevel.INTERNAL_PUBLIC: MaskingMode.NONE,
    ClassificationLevel.INTERNAL_SENSITIVE: MaskingMode.PARTIAL,
    ClassificationLevel.CONFIDENTIAL: MaskingMode.PARTIAL,
    ClassificationLevel.HIGHLY_CONFIDENTIAL: MaskingMode.HASH,
    ClassificationLevel.RESTRICTED: MaskingMode.FULL,
    ClassificationLevel.TOP_SECRET: MaskingMode.FULL,
}

#5.3 Audit Integration

High-classification data access automatically triggers audit recording:

Python
class ClassificationAuditTrigger:
    """Classification-driven audit trigger"""

    AUDIT_THRESHOLDS = {
        ClassificationLevel.INTERNAL_SENSITIVE: AuditLevel.BASIC,
        ClassificationLevel.CONFIDENTIAL: AuditLevel.STANDARD,
        ClassificationLevel.HIGHLY_CONFIDENTIAL: AuditLevel.DETAILED,
        ClassificationLevel.RESTRICTED: AuditLevel.COMPREHENSIVE,
        ClassificationLevel.TOP_SECRET: AuditLevel.FORENSIC,
    }

    async def on_data_access(
        self,
        classification: ClassificationLevel,
        access_event: DataAccessEvent,
    ) -> None:
        audit_level = self.AUDIT_THRESHOLDS.get(classification)
        if audit_level:
            await self._audit_service.record(
                event=access_event,
                level=audit_level,
                classification=classification,
            )

#6. Classification Management Workflow

#6.1 Initial Classification Process

Code
Schema Registration → Auto-Classification Engine → Human Review → Label Activation
         │                     │                       │              │
         │               Rule matching          Security team    ABAC policies
         │               ML classifier         Compliance team   Masking policies
         │                                                        Audit policies

#6.2 Classification Change Workflow

Python
class ClassificationChangeRequest(BaseModel):
    """Classification change request"""

    id: str
    object_type: str
    field_name: str
    current_classification: ClassificationLevel
    requested_classification: ClassificationLevel
    reason: str
    requester: str
    requested_at: datetime

    approvers: list[str] = Field(default_factory=list)
    approval_status: ApprovalStatus = Field(default=ApprovalStatus.PENDING)

    @validator("requested_classification")
    def validate_downgrade(cls, v, values):
        """Downgrades require additional approval"""
        current = values.get("current_classification")
        if current and v < current:
            values["approvers"] = ["security_team_lead", "compliance_officer"]
        return v

#6.3 Periodic Review

Python
class ClassificationReviewScheduler:
    """Classification review scheduler"""

    REVIEW_INTERVALS = {
        ClassificationLevel.TOP_SECRET: timedelta(days=90),
        ClassificationLevel.RESTRICTED: timedelta(days=180),
        ClassificationLevel.HIGHLY_CONFIDENTIAL: timedelta(days=365),
        ClassificationLevel.CONFIDENTIAL: timedelta(days=365 * 2),
    }

    async def schedule_reviews(self) -> list[ReviewTask]:
        tasks = []
        for obj_type in await self._schema_registry.list_object_types():
            for field_name, prop in obj_type.properties.items():
                if prop.classification is None:
                    continue
                interval = self.REVIEW_INTERVALS.get(prop.classification.level)
                if interval is None:
                    continue
                if datetime.utcnow() - prop.classification.labeled_at > interval:
                    tasks.append(ReviewTask(
                        object_type=obj_type.api_name,
                        field_name=field_name,
                        current_classification=prop.classification,
                        due_date=prop.classification.labeled_at + interval,
                    ))
        return tasks

#7. Testing Strategy

#7.1 Classification Correctness Tests

Python
class TestClassification:
    def test_auto_classify_pii_fields(self):
        classifier = RuleBasedClassifier()
        result = classifier.classify_field("ssn", "string", "Social Security Number")
        assert result is not None
        assert result.level == ClassificationLevel.HIGHLY_CONFIDENTIAL
        assert result.category == DataCategory.PII

    def test_propagation_high_water_mark(self):
        propagator = ClassificationPropagator()
        sources = [
            make_label(ClassificationLevel.INTERNAL_SENSITIVE),
            make_label(ClassificationLevel.CONFIDENTIAL),
        ]
        result = propagator.propagate_on_transform(sources, "join")
        assert result.level == ClassificationLevel.CONFIDENTIAL

    def test_object_effective_classification(self):
        obj = ObjectTypeDefinition(
            api_name="Customer",
            display_name="Customer",
            description="Customer object",
            properties={
                "name": PropertyDefinition(
                    name="name", display_name="Name", data_type=DataType.STRING,
                    classification=make_label(ClassificationLevel.INTERNAL_SENSITIVE),
                ),
                "ssn": PropertyDefinition(
                    name="ssn", display_name="SSN", data_type=DataType.STRING,
                    classification=make_label(ClassificationLevel.HIGHLY_CONFIDENTIAL),
                ),
            },
        )
        assert obj.compute_effective_classification() == ClassificationLevel.HIGHLY_CONFIDENTIAL

#8. Production Best Practices

#8.1 Classification Governance Principles

  1. Default conservative: Unclassified fields default to B1 (Internal Sensitive), not Public
  2. High-water mark: After data combination or transformation, adopt the highest classification from all sources
  3. Periodic review: C1 and above reviewed at least annually; D-level reviewed quarterly
  4. Change auditing: All classification changes logged in audit trail; downgrades require dual approval

#8.2 Regulatory Mapping

RegulationRelevant Data CategoryRecommended Minimum Classification
GDPRPIIB2 (Confidential)
HIPAAPHIC1 (Highly Confidential)
PCI DSSPCIC1 (Highly Confidential)
CCPAPIIB2 (Confidential)
SOXFinancialB2 (Confidential)

#8.3 Operational Recommendations

  • Automatically trigger classification engine when new Ontology object types are added
  • Classification results require human review before serving as ABAC policy inputs
  • Establish classification dashboards monitoring distribution and access patterns per tier
  • Set up alert notifications for classification changes on C2/D-level data

#9. Summary

The coomia-dip 7-tier data classification system provides a unified metadata foundation for security subsystems through fine-grained classification levels. Key design highlights:

  1. 7-tier granularity: Covers the complete sensitivity spectrum from public to top secret
  2. Auto-classification: Rule engine + ML classifier achieve high-confidence automatic labeling
  3. Propagation mechanism: Classification labels propagate automatically with data flow, ensuring consistency
  4. System integration: Deep integration with access control, dynamic masking, and audit subsystems
  5. Compliance alignment: Built-in regulatory mappings for GDPR, HIPAA, PCI DSS, and more

The next article will explore the coomia-dip audit trail system and its 13 audit event types.