HabileLabs

Aadhaar Masking on AWS: deployment and user guide

Deploy in one click, make your first request, and run it in your own AWS account.

For version 1.5.0 on AWS Marketplace, by HabileLabs. Questions: support@habilelabs.io.

Aadhaar Masking finds Aadhaar numbers and Aadhaar QR codes in KYC documents and covers them. It masks card scans, phone photos, e-Aadhaar printouts, multi-page loan PDFs, ZIP archives and Excel sheets. It runs entirely inside your own AWS account: one CloudFormation stack, your VPC, your S3 bucket. No document is sent to HabileLabs or anyone else; by default the stack sends HabileLabs only a daily page count (section 5), which you can switch off.

1. Before you start

2. Deploy in one click

  1. Open Launch stack from the product's usage instructions on AWS Marketplace, or this link: Launch stack in Mumbai.
  2. Check that the console shows Asia Pacific (Mumbai) at the top right.
  3. Under Network (required), pick your VPC and two or more of its subnets in different Availability Zones.
  4. Under Alerts (recommended), enter an e-mail address for alarms. You will get one e-mail from AWS SNS to confirm the subscription.
  5. Leave everything else as it is. Tick I acknowledge that AWS CloudFormation might create IAM resources and choose Create stack.
  6. Wait for CREATE_COMPLETE, about 8 to 10 minutes. The Outputs tab then shows what you need:
Output What it is
ApiEndpoint The API's base URL
ApiKeysSecretArn The Secrets Manager secret that holds your API keys
LoadBalancerDnsName Point your own DNS name here (CNAME) if you use one
AlarmTopicArn The SNS topic every alarm goes to
OutputBucketName The S3 bucket for uploads and masked copies
MaskingFunctionName The masking function, for logs and metrics

What the stack creates:

3. Settings

Only the network is required. Everything else has a working default.

Setting Default Change it when
VPC, Subnets none (required) Always: pick a VPC, then two or more of its subnets (the list shows every VPC's subnets; match the VPC ID)
Public IP for tasks ENABLED Your subnets are private with a NAT gateway or VPC endpoints: DISABLED
Alarm e-mail none Recommended: who should hear about alarms
Endpoint type internal Callers outside your network must reach it: internet-facing (needs the next two)
ACM certificate ARN none Internet-facing: a certificate in this Region for your hostname
Your API URL none With a certificate: https:// plus your hostname, used in the links the API returns
Allowed callers (CIDR) 0.0.0.0/0 Internet-facing: your callers' ranges. Internal: optional narrowing
Parallel masking environments 40 More simultaneous traffic: raise. Small quota: lower (10 still works, long PDFs take longer)
Always-warm environments 0 The first request after idle must be fast: 1 or more (about USD 95 a month each)
Send HabileLabs a daily page count (ShareUsage) true You do not want the daily count sent: false (section 5)
Images empty: this version's images Never; leave both empty, so every update brings that version's images

4. Your first request

Get your API key. In Secrets Manager, open the secret named in ApiKeysSecretArn and choose Retrieve secret value; the key is under initial. From a shell:

aws secretsmanager get-secret-value --secret-id <ApiKeysSecretArn> --query SecretString --output text

Call the API from inside your network. With the default internal endpoint, call it from a server in the VPC (EC2, ECS, Lambda in the VPC), from a connected network, or from AWS CloudShell in a VPC environment.

curl -X POST "<ApiEndpoint>/aadhaar-masking" -H "aadhaar-masking-key: <your key>" -F "file=@kyc-card.jpg"

An image or a short PDF is answered at once (200) with a link to the masked file:

{ "status": 200, "message": "File processed successfully.",
  "downloadUrl": "https://...", "maskedPages": 1, "maskingStatus": true }

Download the masked file promptly: the link expires after 15 minutes, and the bucket deletes uploads and masked copies after a day.

Long PDFs and ZIP archives are masked in the background. The answer is 202 with a taskId and a statusUrl; poll the status URL with the same key until status is COMPLETED, then use its downloadUrl. A 500-page PDF takes about a minute. A ZIP comes back as one masked archive with a per-file report.

More:

Files: JPG, PNG, TIFF and PDF up to 100 MB, ZIP up to 500 MB, and Excel (.xls, .xlsx) through POST /aadhaar-masking-excel. Password-protected PDFs are refused, not masked.

What is masked:

5. Your contract and page usage

curl "<ApiEndpoint>/usage" -H "aadhaar-masking-key: <your key>"
{ "subscription": "active", "packs": {"starter": 1}, "pagesAllowance": 250000,
  "pagesUsed": 1234, "contractYearStart": "...", "contractYearEnd": "...", "countedAt": "..." }

Usage reporting (ShareUsage)

From 1.4.0, while ShareUsage is true (the default), the API sends HabileLabs one small report a day, early in the morning (UTC). It contains:

It contains no documents, no Aadhaar numbers, no file names and nothing a document contains. The request is signed with the API task's own AWS credentials, so HabileLabs knows which AWS account sent it without any key to manage. HabileLabs uses it to see your installs and usage in the HabileLabs Marketplace portal, to tell you before you run out of pages or your contract ends, and to support you.

6. Making the API reachable

The API is then served over HTTPS only (TLS 1.2 and 1.3). - AWS WAF in front of the API limits each address to 300 requests in five minutes, blocks addresses on AWS's IP reputation list, and refuses large bodies outside the upload routes. Every request also needs a valid API key. - API keys: to add or rotate one, edit the secret. It is a JSON object of name to key, for example {"initial": "...", "loans-app": "..."}. Changes apply without a redeploy.

7. Security and data handling

8. Alarms

Every alarm publishes to the AlarmTopicArn topic. Subscribe your e-mail, pager or chat hook to it.

Alarm Meaning
no-subscription No live AWS Marketplace contract; masking is refused
page-allowance This contract year reached 80 % or 100 % of its pages
lambda-throttles All parallel environments busy; requests wait or go to the background. Consider raising Parallel masking environments
lambda-errors, lambda-duration-p95 The masking function failed or ran close to its limit
alb-5xx-rate, api-no-healthy-task The API is failing or down
documents-rejected A document was refused because a page could not be masked

9. Costs

10. Updating to a new version

When a new version is announced:

  1. Open CloudFormation > your stack > Update > Replace current template, with the new version's template URL (in its usage instructions).
  2. Keep your settings, but check that the two image fields are empty: empty means "this version's images". A stack created from 1.3.0 or earlier has addresses filled in there; clear them, or the stack keeps its old images.
  3. Check Send HabileLabs a daily page count: an update to 1.4.0 from an earlier version starts with its default, true.
  4. Choose Update stack.

The stack copies the new engine image and switches over without downtime.

11. Removing it

Delete the stack in CloudFormation. Its two S3 buckets (masked files, load-balancer logs) are kept on purpose, so that no file is lost by accident. The files bucket empties itself within a day or two; delete both buckets once they are empty. A log group named /aws/lambda/<stack>-ImageCopyFunction-… can reappear after the deletion (the copy function's last lines arrive after its log group is removed); delete it too. Your AWS Marketplace contract is separate: cancel or let it end in Manage subscriptions.

12. Troubleshooting

What you see What to do
Create stack refused: "Pick subnets from the VPC you selected" The subnet list shows every VPC's subnets: choose only those whose VPC ID matches the VPC field
Stack fails: "ReservedConcurrentExecutions ... below its minimum value of [100]" The account's Lambda quota is under 140: lower Parallel masking environments, or ask AWS for a higher quota
403 {"error": "Forbidden"} The API key is missing or wrong: header aadhaar-masking-key
403 "No active AWS Marketplace subscription for this product" Subscribe, or renew, with this account; the API notices within a minute
Connection times out Internal endpoint: call from inside the VPC or a connected network, and check Allowed callers
202 instead of 200 Normal for long PDFs, ZIPs and busy moments: poll the statusUrl
422 Unsupported file type, file too large, or a password-protected PDF
403 with a plain page instead of JSON AWS WAF blocked it: more than 300 requests in five minutes from one address, or an address on AWS's reputation list
lambda-throttles alarm Raise Parallel masking environments (and your Lambda quota if needed)
usage_report_refused with 403 in the API log The stack runs in an AWS account other than the subscribing one; tell support which account, or set ShareUsage to false
usage_report_retry every day The API tasks cannot reach the internet (private subnets without NAT); nothing else is affected

13. Support

E-mail support@habilelabs.io with your AWS account ID, the stack name and, for a specific request, the x-request-id header from its answer. We answer within one business day (IST, Monday to Friday).

Masking is automatic. Handwritten numbers and Virtual IDs (VID) are not masked. For high-stakes uses, spot-check results.