# n8n-nodes-gcloud-sa-impersonate

A custom n8n node for impersonating Google Cloud Service Accounts to generate access tokens.

## Features

- 🔐 Impersonate Google Cloud Service Accounts without credentials
- 🚀 Generate access tokens with configurable lifetime
- ⚙️ Configurable GCE metadata server URL
- 🎯 Support for custom scopes and delegation chains
- 🐳 Docker-based development environment with GCE metadata server emulator

## Installation

### For Development

1. Clone the repository:
```bash
git clone https://github.com/your-username/n8n-nodes-gcloud-sa-impersonate.git
cd n8n-nodes-gcloud-sa-impersonate
```

2. Install dependencies:
```bash
npm install
```

3. Build the node:
```bash
npm run build
```

### Using Docker Compose (Recommended for Testing)

This project includes a complete Docker Compose setup with a GCE metadata server emulator for testing.

#### Prerequisites

1. **Google Cloud Authentication**: Set up Application Default Credentials
```bash
gcloud auth application-default login
```

2. **Service Account Permissions**: Ensure your user account has the following IAM permissions on the target service account:
```bash
# Replace with your email and service account
gcloud iam service-accounts add-iam-policy-binding \
  YOUR_SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com \
  --member="user:your-email@domain.com" \
  --role="roles/iam.serviceAccountTokenCreator"

gcloud iam service-accounts add-iam-policy-binding \
  YOUR_SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com \
  --member="user:your-email@domain.com" \
  --role="roles/iam.serviceAccountUser"
```

#### Setup Steps

1. **Set environment variables**:
```bash
# Required: Your Google Cloud Project details
export GOOGLE_PROJECT_ID=your-project-id
export GOOGLE_NUMERIC_PROJECT_ID=123456789012
export GOOGLE_SERVICE_ACCOUNT=your-service-account@your-project-id.iam.gserviceaccount.com

# Required: Access token for GCE metadata server emulator
# Get this value by running: gcloud auth print-access-token
export GOOGLE_ACCESS_TOKEN=$(gcloud auth print-access-token)
```

2. **Create a `.env` file** (optional, for docker-compose):
```bash
# Copy environment variables to .env file for docker-compose
cat << EOF > .env
GOOGLE_PROJECT_ID=${GOOGLE_PROJECT_ID}
GOOGLE_NUMERIC_PROJECT_ID=${GOOGLE_NUMERIC_PROJECT_ID}
GOOGLE_SERVICE_ACCOUNT=${GOOGLE_SERVICE_ACCOUNT}
GOOGLE_ACCESS_TOKEN=${GOOGLE_ACCESS_TOKEN}
EOF
```

3. **Generate metadata server configuration**:
```bash
# This script uses the environment variables above to generate metadata-config/config.json
./bin/gen-config-json.sh
```

4. **Copy your ADC credentials**:
```bash
cp ~/.config/gcloud/application_default_credentials.json ./adc.json
```

#### Running the Stack

1. **Start the services**:
```bash
docker-compose up --build
```

2. **Access n8n**:
- URL: http://localhost:5678
- Username: `admin`
- Password: `admin`

3. **Get fresh access token** (refresh every ~1 hour):
```bash
export GOOGLE_ACCESS_TOKEN=$(gcloud auth print-access-token)
docker-compose up -d
```

## Node Configuration

When creating a workflow in n8n, configure the "Google Cloud SA Impersonate" node with:

| Parameter | Description | Default | Example |
|-----------|-------------|---------|---------|
| **GCE Metadata Server URL** | Metadata server endpoint | `https://metadata.google.internal/` | `http://gce-metadata:8080` (for Docker) |
| **Target Service Account Email** | Service account to impersonate | - | `my-sa@project.iam.gserviceaccount.com` |
| **Scopes** | OAuth 2.0 scopes (comma-separated) | `https://www.googleapis.com/auth/cloud-platform` | `https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/storage` |
| **Delegates** | Delegation chain (optional) | - | `delegate1@project.iam.gserviceaccount.com` |
| **Token Lifetime** | Access token lifetime | `300s` | `3600s`, `1h` |

### Example Node Output

```json
{
  "accessToken": "ya29.c.b0Aaekm1....",
  "expireTime": "2024-08-07T06:32:18Z",
  "targetServiceAccount": "impersonate-test@project.iam.gserviceaccount.com",
  "scopes": ["https://www.googleapis.com/auth/cloud-platform"],
  "lifetime": "300s"
}
```

## Troubleshooting

### Common Issues

1. **403 Permission Error**:
   - Ensure service account impersonation permissions are granted
   - Check Organization Policies for impersonation restrictions
   - Verify IAM Credentials API is enabled

2. **GCE Metadata Server Connection Failed**:
   - For Docker: Use `http://gce-metadata:8080`
   - For GCE instances: Use `https://metadata.google.internal/`
   - Check container networking and port accessibility

3. **Invalid Access Token**:
   - Refresh the `GOOGLE_ACCESS_TOKEN` environment variable
   - Ensure ADC credentials (`adc.json`) are up to date

### Debug Commands

```bash
# Test service account impersonation directly
gcloud auth print-access-token --impersonate-service-account=YOUR_SA@PROJECT.iam.gserviceaccount.com

# Check metadata server emulator
curl -H "Metadata-Flavor: Google" http://localhost:8080/computeMetadata/v1/instance/service-accounts/default/token

# View container logs
docker-compose logs gce-metadata
docker-compose logs n8n
```

## Development

### Building the Node

```bash
npm run build
```

### Linting and Formatting

```bash
npm run lint
npm run format
```

### Testing

The Docker Compose setup provides an isolated testing environment with:
- n8n instance with the custom node pre-installed
- GCE metadata server emulator for testing without actual GCE instances
- Persistent data volumes for n8n workflows

## Architecture

```
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   n8n Node      │───▶│ GCE Metadata    │───▶│ Google Cloud    │
│                 │    │ Server Emulator │    │ IAM API         │
└─────────────────┘    └─────────────────┘    └─────────────────┘
```

1. **n8n Node** requests access token from metadata server
2. **GCE Metadata Server Emulator** authenticates using your ADC credentials
3. **Google Cloud IAM API** performs service account impersonation
4. Access token is returned through the chain

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
